C# vs. C++: co jest rdzeniem?

Opublikowany: 2022-03-11

W szybko zmieniającym się świecie inżynierii oprogramowania różne języki programowania walczą o swoje miejsce w branży. Jednak różne języki stosują różne paradygmaty i zwykle mają długie listy zalet i wad, co sprawia, że ​​bezpośrednie porównania między nimi są trudne i niejednoznaczne.

Niektóre języki mają jednak podobną składnię i skupienie, więc warto porównywać je obok siebie. W tym artykule zbadamy różnicę między C++ i C# i porównamy te płodne języki programowania.

Krótka historia C# i C++

W latach 70., gdy duński informatyk Bjarne Stroustrup pracował nad swoją rozprawą doktorską, chciał użyć Simula, pierwszego języka programowania obiektowego. Jednak Simula okazała się zbyt wolna, więc Stroustrup zdecydował się na użycie C, który był – a niektórzy twierdzą, że nadal jest – najszybszym językiem programowania.

Obraz przedstawia dwa paski przedstawiające różne wersje C# i C++ od 1998 do 2021, począwszy od C++ w 1998 i C# 1.0 w 2002. Najnowsze wersje to C++ 20 w 2020 i C# 10.0 w 2021.
Kalendarium wydań C# i C++

Po doświadczeniach z Simulą Stroustrup zaczął rozwijać język obiektowy oparty na C, a do 1985 roku C++ został udostępniony publicznie.

Postanowił, że C++ będzie „jak najbliżej C, ale nie bliżej”, co oznacza, że ​​adopcja nie będzie przeszkodą. Ponieważ wszystkie biblioteki C były automatycznie dostępne do użytku, wielu czołowych programistów C było w stanie przejść na C++, wykorzystując swoją dotychczasową wiedzę.

Niestety, wrodzone podobieństwo do C było również jednym z najsłabszych punktów C++, ponieważ oba języki wymagały stromych krzywych uczenia się i były trudne do opanowania, co sprawiało, że kodowanie było wyzwaniem dla niedoświadczonych programistów.

Był to jeden z głównych powodów decyzji Sun Microsystems o stworzeniu Javy w połowie lat 90-tych. Java miała składnię podobną do C++, ale upraszczała konstrukcje językowe i zmniejszała ryzyko niezamierzonych błędów. Zespół Java, kierowany przez Jamesa Goslinga, osiągnął to głównie poprzez porzucenie wstecznej kompatybilności z C.

W 2002 roku Microsoft wydał C# jako bezpośredni konkurent Javy. Jako język alternatywny, C# dzieli pewną składnię z Javą, ale ma więcej funkcji. Zarówno C#, jak i C++ zostały znacznie ulepszone od czasu ich wydania.

Obiektowe języki programowania z zastrzeżeniem

Kiedy pojawił się C++, większość języków programowania była zorientowana na procedury.

W proceduralnych językach programowania program jest zorganizowany w mniejsze jednostki, zwane procedurami. Każda procedura odpowiada jakiejś wspólnej akcji, która jest używana później (wywoływana z) w większej jednostce.

W językach obiektowych procedury są pogrupowane wokół obiektów, na których są wykonywane. Obiekt jest jednostką logiczną, która posiada pewien stan.

C# jest językiem w pełni zorientowanym obiektowo, podczas gdy C++ to język, który może mieszać kod proceduralny i zorientowany obiektowo.

Podobieństwa między C# i C++

Oba języki są zorientowane obiektowo i oparte na C. Co więcej, C# jest oparty na C++, co czyni je dość podobnymi. Osoby, które nie znają biegle żadnego języka, mogą łatwo pomylić jeden z drugim, zerkając na kod.

Oba języki mają cechy powszechnie spotykane w językach obiektowych, w tym:

  • Kapsułkowanie. Kod jest zorganizowany w logiczne grupy, zwane klasami.
  • Ukrywanie danych. Części danych i kodu są prywatne, co oznacza, że ​​można uzyskać do nich dostęp tylko z poziomu klasy.
  • Dziedzictwo. Funkcjonalność klas współużytkowanych można zorganizować we wspólnej klasie dziedziczonej przez klasy pochodne, dzięki czemu można uniknąć powielania kodu.
  • Wielopostaciowość. Kod może wpływać na obiekt klasy bazowej, ale zachowuje się inaczej dla różnych klas pochodnych.

Różnice między C# a C++

Niektóre zaawansowane funkcje C++ są trudne do zrozumienia i mogą powodować błędy programistyczne. Te funkcje zostały celowo pominięte w Javie, a następnie w C#:

  • Dziedziczenie wielokrotne. Klasy pochodne dziedziczą wiele klas bazowych. Zamiast tej funkcji C# wprowadził klasy podstawowe bez implementacji. Takie klasy nazywane są w C# interfejsami.
  • Wskaźniki. Chociaż wskaźników można używać w C#, kod, który używa wskaźników, musi być oznaczony jako „niebezpieczny”. Ta praktyka jest wysoce odradzana i zamiast niej stosowane są referencje.
  • Utrata precyzji. C#nie zezwala na utratę precyzji przez niejawną konwersję typu. Jeśli precyzja ma zostać utracona, wymagana jest jawna konwersja.

Zarządzanie pamięcią

Być może najważniejszą różnicą między C# a C++ jest zarządzanie pamięcią.

W C pamięć dynamiczna (tj. alokacja pamięci nie jest znana z góry) jest alokowana za pomocą funkcji malloc i zwalniana za pomocą free . Od programistów oczekiwano ręcznego zarządzania pamięcią. W rezultacie wycieki pamięci były częstymi błędami w kodzie C.

Zarządzanie pamięcią w C++ zostało ulepszone, ponieważ pamięć jest zarządzana półautomatycznie. Można używać obiektów zwanych „inteligentnymi wskaźnikami”, dzięki czemu programiści nie muszą ręcznie zwalniać pamięci. Istnieją jednak pewne skrajne przypadki (odwołania cykliczne), w których inteligentne wskaźniki są niewystarczające, aby zapobiec wyciekom pamięci.

C# używa modułu odśmiecania pamięci (GC), który automatycznie zwalnia pamięć, która nie jest już używana. Choć może się to wydawać idealne, czasami GC sprawia, że ​​trudno jest zwolnić obiekt, który przechowuje zasoby systemowe inne niż pamięć (np. uchwyty plików lub połączenia TCP). W takim przypadku może wystąpić zjawisko znane jako „wyciek zasobów”, a programista musi ręcznie cofnąć alokację obiektu, który przechowuje zasoby. W tych rzadkich sytuacjach cofnięcie alokacji w C# staje się bardziej skomplikowane niż w C++, ponieważ niszczenie obiektów w C# nie jest deterministyczne.

Kompilacja: pliki binarne a kod bajtowy

C++ jest natychmiast kompilowany do maszynowego kodu binarnego. C# jest kompilowany do kodu bajtowego, który jest później kompilowany w maszynowym kodzie binarnym przez platformę .NET. (Wcześniej „.NET Core”, .NET to nowoczesny, wieloplatformowy zamiennik oryginalnej platformy .NET firmy Microsoft).

Chociaż C++ ma przewagę wydajności w tych różnych podejściach do kompilacji, C# ma zaawansowaną funkcję o nazwie „odbicie”, która umożliwia tworzenie wystąpień obiektów i wywoływanie metod na podstawie informacji zebranych w czasie wykonywania. Na przykład można wywołać metodę po jej nazwie, chociaż ta metoda nie była dostępna w czasie kompilacji. C++ z definicji nie może mieć odbicia, ponieważ jest kompilowany natychmiast. C++ ma zamiast tego informacje o typie czasu wykonywania (RTTI). Jest to znacznie mniej wydajna funkcja, ponieważ jest używana tylko dla typów z funkcjami wirtualnymi.

C++ posiada również szablony w postaci kodu, który generuje się w czasie kompilacji w zależności od typów zmiennych. Zamiast szablonów C# ma generyki. Ogólne nie są rozwiązywane w czasie kompilacji, ale w czasie wykonywania. W związku z tym szablony są szybsze niż generyczne. Z drugiej strony, generyki nie wymagają dodatkowej pamięci dla każdego nowego typu zmiennej.

Porównanie funkcji

Funkcja C++ C#
Kompilacja Bezpośrednio do binarnego Do kodu bajtowego
Czas kompilacji Długi Krótki
Zarządzanie pamięcią Ręczny lub półautomatyczny za pomocą inteligentnych wskaźników Automatycznie przez śmieciarza
Prędkość w czasie pracy Tak szybko, jak to tylko możliwe Wolniej niż C++
Wymagania dotyczące pamięci w czasie wykonywania Optymalny Więcej niż C++
Podatne na błędy Podatny na błędy dla niedoświadczonych programistów Bardziej przyjazny dla początkujących
Dziedziczenie klas Pojedyncze, wielokrotne i wirtualne Tylko jeden, wiele z interfejsami
Kod ogólny Szablony — czas kompilacji Generyki — czas wykonywania
Ruchliwość Kompilatory dostępne dla praktycznie wszystkich systemów operacyjnych, ale kod musi być skompilowany dla każdego celu Skompilowany kod bajtowy może działać w wielu systemach operacyjnych
Uczenie się Stroma krzywa uczenia się; czasochłonne; może być złożony dla początkujących programistów; mniejsza społeczność z mniejszą liczbą produkowanych zasobów edukacyjnych język wysokiego poziomu; łatwiejszy do odczytania; hierarchia klas wyższych; łatwiejszy do opanowania dla początkujących, zwłaszcza tych z doświadczeniem C++ lub Java; większa i bardziej aktywna społeczność
Odbicie Niedostępne, informacje o typie czasu wykonywania są kiepskim zamiennikiem Dostępne i bardzo wygodne
Niejawna konwersja Tolerancja dla typów wbudowanych Dozwolone tylko wtedy, gdy jest bezpieczne
Kompatybilność z C W pełni kompatybilny z zewnętrznym kodem C Nie kompatybilne
Modułowość Zrealizowany za pomocą bibliotek i nagłówków Wbudowany w język

C# vs. C++: który język jest lepszy?

Jeśli chodzi o szybkość i wydajność pamięci, C++ jest wyraźnym zwycięzcą. Jednakże, jeśli dobra biblioteka C# jest łatwo dostępna, ale nie jest dostępna dla C++, C# może ostatecznie zapewnić szybsze rozwiązanie, a implementacja C++ może okazać się wolniejsza.

Programowanie jest zwykle szybsze w C#. Jeśli aplikacja nie wykonuje zadań krytycznych czasowo, warto wybrać łatwiejszy i mniej podatny na błędy język.

Tradycyjnie C++ był właściwym wyborem dla środowiska innego niż Windows, ale to się zmieniło, gdy Microsoft zaczął zachęcać do implementacji open source .NET. Ten sam kod bajtowy C# może działać na praktycznie każdej platformie, co sprawia, że ​​jest to preferowany język, jeśli chodzi o uproszczenie przenośności.

Ze względu na refleksję, C# jest bardziej rozsądnym wyborem podczas pisania bibliotek, które muszą obsługiwać zdalne wywoływanie funkcji lub podobne funkcje, które wymagają generowania kodu przy użyciu informacji dostępnych w czasie wykonywania.

Chociaż oba języki obsługują projektowanie modułowe, trudniej jest utrzymać je w C++, które implementuje tę funkcję za pomocą nagłówków zaprojektowanych w C — metodzie, którą obecnie przewyższają bardziej nowoczesne podejścia. Zwykle powoduje to C++ czas kompilacji, który jest znacznie dłuższy niż czas kompilacji C# do kodu bajtowego.

C++ jest bardziej skomplikowanym językiem, więc programiści C++ mogą łatwiej przejść do C# niż na odwrót. Ale jeśli Twój zespół zawiera zarówno programistów C++, jak i C#, możliwe jest mieszanie tych dwóch języków.

Wybór odpowiedniego języka

Jeśli potrzebujesz wysokiej wydajności, odpowiedzią jest C++ w prawie wszystkich sytuacjach. „Wysoka wydajność” odnosi się do kodu. Jeśli używasz łatwo dostępnych bibliotek do pracy, w której czas ma krytyczne znaczenie, wydajność Twojego kodu może nie być czynnikiem decydującym.

Jeśli wydajność nie jest krytyczna, należy wziąć pod uwagę czas opracowania. Jeśli możesz zacząć od zera, prawdopodobnie lepszym wyborem będzie tworzenie projektu w C#.

Jeśli masz trochę czasu na rozwój, ale wydajność nie jest krytyczna, wybór zależy od umiejętności dostępnych programistów. Pamiętaj, że płynność twoich programistów może poważnie wpłynąć na przyszłą konserwację kodu. Jeśli to możliwe, weź pod uwagę język preferowany przez Twój zespół.