Analogicznie, C # jest w zasadzie zestawem narzędzi dla mechaników, w których ktoś przeczytał, że ogólnie należy unikać szczypiec i kluczy nastawnych, więc w ogóle nie zawiera kluczy nastawnych, a szczypce są zamknięte w specjalnej szufladzie oznaczonej jako „niebezpieczne” , i można z niego korzystać wyłącznie za zgodą przełożonego, po podpisaniu zrzeczenia się odpowiedzialności zwalniającej pracodawcę z odpowiedzialności za zdrowie.
Dla porównania, C ++ obejmuje nie tylko klucze nastawne i szczypce, ale także narzędzia specjalne o nieparzystej kuli, których cel nie jest od razu widoczny, a jeśli nie znasz właściwego sposobu ich trzymania, mogą z łatwością odciąć twoje kciuk (ale gdy zrozumiesz, jak z nich korzystać, możesz robić rzeczy, które są zasadniczo niemożliwe za pomocą podstawowych narzędzi w przyborniku C #). Ponadto ma tokarkę, frezarkę, szlifierkę do powierzchni, piłę taśmową do cięcia metalu itp., Aby umożliwić projektowanie i tworzenie całkowicie nowych narzędzi za każdym razem, gdy poczujesz taką potrzebę (ale tak, narzędzia tych mechaników mogą i będą powodować poważne obrażenia, jeśli nie wiesz, co z nimi robisz - lub nawet po prostu nieostrożnie).
Odzwierciedla to podstawową różnicę w filozofii: C ++ stara się zapewnić ci wszystkie narzędzia, których możesz potrzebować w zasadzie do każdego projektu, jaki chcesz. Prawie nie próbuje kontrolować sposobu korzystania z tych narzędzi, dlatego łatwo jest ich używać do tworzenia projektów, które działają dobrze tylko w rzadkich sytuacjach, a także projektów, które są prawdopodobnie kiepskim pomysłem i nikt nie wie o sytuacji, w której prawdopodobnie będą w ogóle dobrze działać. W szczególności wiele z tego odbywa się poprzez oddzielenie decyzji projektowych - nawet tych, które w praktyce są prawie zawsze powiązane. W rezultacie istnieje ogromna różnica między zwykłym pisaniem w C ++, a dobrym pisaniem w C ++. Aby dobrze pisać w C ++, musisz znać wiele idiomów i praktycznych reguł (w tym praktycznych zasad, jak poważnie przemyśleć ponownie, zanim złamiesz inne reguły). W rezultacie, C ++ jest zorientowany bardziej na łatwość obsługi (przez ekspertów) niż na łatwość uczenia się. Są również (zbyt wiele) okoliczności, w których korzystanie z nich nie jest zbyt trudne.
C # robi o wiele więcej, aby narzucić (lub przynajmniej bardzo mocno zasugerować) to, co projektanci języków uważają za dobre praktyki projektowe. Sporo rzeczy, które są oddzielone w C ++ (ale zwykle idą razem w praktyce), są bezpośrednio połączone w języku C #. Pozwala to „niebezpiecznemu” kodowi nieco przekraczać granice, ale szczerze mówiąc, nie za dużo.
Rezultat jest taki, że z jednej strony istnieje całkiem sporo projektów, które mogą być wyrażane dość bezpośrednio w C ++, które są znacznie bardziej niezdarne do wyrażenia w języku C #. Z drugiej strony, jest to cały dużo łatwiej uczyć się C #, a szanse na produkcję naprawdę straszny projekt, który nie będzie działać w danej sytuacji (lub prawdopodobnie jakiekolwiek inne) są znacznie zmniejszone. W wielu (prawdopodobnie nawet w większości) przypadkach można uzyskać solidny, wykonalny projekt, po prostu „płynąc z prądem”, że tak powiem. Lub, jak jeden z moich przyjaciół (przynajmniej lubię myśleć o nim jako o przyjacielu - nie jestem pewien, czy naprawdę się zgadza) lubi to ująć, C # ułatwia wpadnięcie w pułapkę sukcesu.
Patrząc dokładniej na pytanie, w jaki sposób class
i struct
jak się mają w dwóch językach: obiekty utworzone w hierarchii dziedziczenia, w których można użyć obiektu klasy pochodnej pod przykrywką jego klasy podstawowej / interfejsu, jesteś w zasadzie utknąłem w fakcie, że zwykle musisz to zrobić za pomocą jakiegoś wskaźnika lub odwołania - na konkretnym poziomie dzieje się tak, że obiekt klasy pochodnej zawiera pamięć, którą można traktować jako instancję klasy podstawowej / interfejs, a obiektem pochodnym jest manipulowany przez adres tej części pamięci.
W C ++ programista musi to zrobić poprawnie - gdy korzysta z dziedziczenia, do niego należy upewnienie się, że (na przykład) funkcja, która działa z klasami polimorficznymi w hierarchii, robi to za pomocą wskaźnika lub odwołania do bazy klasa.
W języku C # to, co jest zasadniczo tym samym podziałem między typami, jest znacznie bardziej wyraźne i wymuszone przez sam język. Programista nie musi podejmować żadnych kroków, aby przekazać instancję klasy przez referencję, ponieważ tak się stanie domyślnie.
struct
nie zawsze są przechowywane na stosie; rozważ obiekt zstruct
polem. Poza tym, jak wspomniał Mason Wheeler, problem krojenia jest prawdopodobnie największym powodem.