Per analogia, C # è fondamentalmente come un set di strumenti per meccanici in cui qualcuno ha letto che dovresti generalmente evitare pinze e chiavi regolabili, quindi non include affatto chiavi regolabili e le pinze sono bloccate in un apposito cassetto contrassegnato "non sicuro" e può essere utilizzato solo con l'approvazione di un supervisore, dopo aver firmato un disclaimer che assolve il datore di lavoro da qualsiasi responsabilità per la propria salute.
Il C ++, al confronto, include non solo chiavi e pinze regolabili, ma alcuni strumenti piuttosto speciali a sfera speciale il cui scopo non è immediatamente evidente e se non conosci il modo giusto di tenerli, potrebbero facilmente tagliare il tuo pollice (ma una volta che hai capito come usarli, puoi fare cose che sono essenzialmente impossibili con gli strumenti di base nella casella degli strumenti di C #). Inoltre, ha un tornio, una fresatrice, una smerigliatrice di superficie, una sega a nastro per il taglio di metalli, ecc., Per consentirti di progettare e creare strumenti completamente nuovi ogni volta che ne senti la necessità (ma sì, quegli strumenti del macchinista possono e causeranno lesioni gravi se non sai cosa stai facendo con loro - o anche solo se ti trascuri).
Ciò riflette la differenza fondamentale nella filosofia: il C ++ tenta di fornirti tutti gli strumenti di cui potresti aver bisogno essenzialmente per qualsiasi progetto tu voglia. Non fa quasi alcun tentativo di controllare il modo in cui usi questi strumenti, quindi è anche facile usarli per produrre progetti che funzionano bene solo in situazioni rare, così come progetti che sono probabilmente solo un'idea schifosa e nessuno sa di una situazione in cui probabilmente funzioneranno bene. In particolare, gran parte di questo viene fatto disaccoppiando le decisioni di progettazione - anche quelle che in pratica sono quasi sempre accoppiate. Di conseguenza, c'è una grande differenza tra scrivere semplicemente C ++ e scrivere bene C ++. Per scrivere bene C ++, devi conoscere molti modi di dire e regole empiriche (comprese le regole empiriche su quanto seriamente riconsiderare prima di infrangere altre regole empiriche). Di conseguenza, Il C ++ è molto più orientato alla facilità d'uso (da parte degli esperti) che alla facilità di apprendimento. Ci sono anche (troppe) circostanze in cui non è nemmeno terribilmente facile da usare.
C # fa molto di più per cercare di forzare (o almeno suggerire in modo estremamente forte) ciò che i progettisti del linguaggio hanno considerato buone pratiche di progettazione. Molte cose che sono disaccoppiate in C ++ (ma di solito vanno insieme in pratica) sono direttamente accoppiate in C #. Permette al codice "non sicuro" di spingere un po 'i confini, ma onestamente, non molto.
Il risultato è che da un lato ci sono alcuni progetti che possono essere espressi in modo abbastanza diretto in C ++ che sono sostanzialmente più goffi da esprimere in C #. D'altra parte, si tratta di un intero molto più facile da imparare il C #, e le possibilità di produzione di un design davvero orribile che non funzionerà per la vostra situazione (o probabilmente qualsiasi altro) sono drasticamente ridotti. In molti (probabilmente anche nella maggior parte dei casi), è possibile ottenere un design solido e realizzabile semplicemente "seguendo il flusso", per così dire. Oppure, come uno dei miei amici (almeno mi piace pensare a lui come un amico - non sono sicuro che sia davvero d'accordo) piace metterlo, C # rende facile cadere nella fossa del successo.
Quindi, osservando più specificamente la domanda su come class
e struct
ottenuto come sono nelle due lingue: oggetti creati in una gerarchia di ereditarietà in cui potresti usare un oggetto di una classe derivata nelle vesti della sua classe / interfaccia di base, sei praticamente bloccato dal fatto che normalmente è necessario farlo tramite una sorta di puntatore o riferimento - a livello concreto, ciò che accade è che l'oggetto della classe derivata contiene qualcosa di memoria che può essere trattato come un'istanza della classe base / interfaccia e l'oggetto derivato viene manipolato tramite l'indirizzo di quella parte della memoria.
In C ++, spetta al programmatore farlo correttamente - quando usa l'ereditarietà, spetta a lui assicurarsi che (ad esempio) una funzione che funzioni con le classi polimorfiche in una gerarchia lo faccia tramite un puntatore o un riferimento alla base classe.
In C #, ciò che è fondamentalmente la stessa separazione tra i tipi è molto più esplicito e applicato dal linguaggio stesso. Il programmatore non ha bisogno di fare alcun passo per passare un'istanza di una classe per riferimento, perché ciò accadrà di default.
struct
i messaggi di posta elettronica non sono sempre memorizzati nello stack; considera un oggetto con unstruct
campo. A parte questo, come menzionato da Mason Wheeler, il problema del taglio è probabilmente il motivo principale.