Widzę tutaj kilka ważnych odpowiedzi, ale zamierzam zagłębić się w szczegóły.
Przejdź do poniższego podsumowania, aby znaleźć odpowiedź na swoje główne pytanie, jeśli nie chcesz przeglądać całej ściany tekstu.
Abstrakcja
Więc w takim razie za co płacę?
Płacisz za abstrakcję . Możliwość pisania prostszego i bardziej przyjaznego dla człowieka kodu ma swoją cenę. W C ++, który jest językiem zorientowanym obiektowo, prawie wszystko jest obiektem. Kiedy używasz dowolnego przedmiotu, pod maską zawsze będą się dziać trzy główne rzeczy:
- Tworzenie obiektów, w zasadzie alokacja pamięci dla samego obiektu i jego danych.
- Inicjalizacja obiektu (zwykle jakąś
init()metodą). Zwykle alokacja pamięci odbywa się pod maską, jako pierwsza rzecz na tym etapie.
- Zniszczenie obiektu (nie zawsze).
Nie widzisz tego w kodzie, ale za każdym razem, gdy używasz obiektu, wszystkie trzy powyższe rzeczy muszą jakoś się wydarzyć. Gdybyś zrobił wszystko ręcznie, kod byłby oczywiście znacznie dłuższy.
Teraz abstrakcję można wydajnie tworzyć bez dodawania narzutu: wbudowywanie metod i inne techniki mogą być używane zarówno przez kompilatory, jak i programistów, aby usunąć narzuty abstrakcji, ale to nie jest Twój przypadek.
Co tak naprawdę dzieje się w C ++?
Oto on, w podziale:
std::ios_baseKlasa jest inicjowany, który jest klasą bazową dla Everything I / O pokrewnych.
std::coutObiekt jest inicjowany.
- Twój ciąg jest ładowany i przekazywany do
std::__ostream_insert, co (jak już zorientowałeś się po nazwie) jest metodą std::cout(w zasadzie <<operator), która dodaje ciąg do strumienia.
cout::endljest również przekazywany do std::__ostream_insert.
__std_dso_handlejest przekazywana do __cxa_atexit, która jest funkcją globalną odpowiedzialną za „czyszczenie” przed wyjściem z programu. __std_dso_handlesama jest wywoływana przez tę funkcję do zwalniania i niszczenia pozostałych obiektów globalnych.
Więc używając C == nie płacisz za nic?
W kodzie C dzieje się bardzo niewiele kroków:
- Ciąg jest załadowany i przekazywane
putsza pośrednictwem edirejestru.
puts zostanie wezwany.
Nie ma żadnych obiektów, więc nie ma potrzeby inicjowania / niszczenia czegokolwiek.
To jednak nie znaczy, że nie jesteś „płacić” za nic w C . Wciąż płacisz za abstrakcję, a także za inicjalizację standardowej biblioteki C i dynamiczne rozwiązywanie printffunkcji (a właściwieputs , która jest optymalizowana przez kompilator, ponieważ nie potrzebujesz żadnego ciągu formatu) nadal odbywa się pod maską.
Gdybyś napisał ten program w czystym asemblerze, wyglądałby mniej więcej tak:
jmp start
msg db "Hello world\n"
start:
mov rdi, 1
mov rsi, offset msg
mov rdx, 11
mov rax, 1 ; write
syscall
xor rdi, rdi
mov rax, 60 ; exit
syscall
Co w zasadzie powoduje tylko wywołanie wywołania write systemowego, po którym następuje wywołanie exitsystemowe. Teraz to byłoby absolutne minimum, aby osiągnąć to samo.
Podsumowując
C jest o wiele bardziej surowy i robi tylko niezbędne minimum, pozostawiając pełną kontrolę użytkownikowi, który jest w stanie w pełni zoptymalizować i dostosować praktycznie wszystko, czego chce. Mówisz procesorowi, aby załadował łańcuch do rejestru, a następnie wywołujesz funkcję biblioteki, aby użyć tego ciągu. Z drugiej strony C ++ jest o wiele bardziej złożony i abstrakcyjny . Ma to ogromną zaletę przy pisaniu skomplikowanego kodu i pozwala na łatwiejszy do napisania i bardziej przyjazny dla człowieka kod, ale oczywiście wiąże się to z kosztami. Zawsze będzie wada wydajności w C ++ w porównaniu z C w takich przypadkach, ponieważ C ++ oferuje więcej niż to, co jest potrzebne do wykonania takich podstawowych zadań, a zatem zwiększa narzut .
Odpowiadając na twoje główne pytanie :
Czy płacę za to, czego nie jem?
W tym konkretnym przypadku tak . Nie wykorzystujesz niczego, co C ++ ma do zaoferowania więcej niż C, ale to tylko dlatego, że w tym prostym fragmencie kodu nie ma nic, w czym C ++ mógłby ci pomóc: jest tak prosty, że w ogóle nie potrzebujesz C ++.
Aha, i jeszcze jedna rzecz!
Zalety C ++ mogą nie wydawać się oczywiste na pierwszy rzut oka, ponieważ napisałeś bardzo prosty i mały program, ale spójrz na nieco bardziej złożony przykład i zobacz różnicę (oba programy robią dokładnie to samo):
C :
#include <stdio.h>
#include <stdlib.h>
int cmp(const void *a, const void *b) {
return *(int*)a - *(int*)b;
}
int main(void) {
int i, n, *arr;
printf("How many integers do you want to input? ");
scanf("%d", &n);
arr = malloc(sizeof(int) * n);
for (i = 0; i < n; i++) {
printf("Index %d: ", i);
scanf("%d", &arr[i]);
}
qsort(arr, n, sizeof(int), cmp)
puts("Here are your numbers, ordered:");
for (i = 0; i < n; i++)
printf("%d\n", arr[i]);
free(arr);
return 0;
}
C ++ :
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void) {
int n;
cout << "How many integers do you want to input? ";
cin >> n;
vector<int> vec(n);
for (int i = 0; i < vec.size(); i++) {
cout << "Index " << i << ": ";
cin >> vec[i];
}
sort(vec.begin(), vec.end());
cout << "Here are your numbers:" << endl;
for (int item : vec)
cout << item << endl;
return 0;
}
Mam nadzieję, że wyraźnie widzisz, co mam na myśli. Zwróć także uwagę, jak w C musisz zarządzać pamięcią na niższym poziomie, używając malloci freejak musisz być bardziej ostrożny przy indeksowaniu i rozmiarach oraz jak musisz być bardzo dokładny podczas przyjmowania danych wejściowych i drukowania.