Por analogia, o C # é basicamente como um conjunto de ferramentas mecânicas em que alguém leu que você geralmente deve evitar alicates e chaves ajustáveis, para que não inclua chaves ajustáveis, e os alicates estão trancados em uma gaveta especial marcada como "insegura" , e só pode ser usado com a aprovação de um supervisor, depois de assinar um aviso de isenção, exonerando seu empregador de qualquer responsabilidade por sua saúde.
O C ++, por comparação, não inclui apenas chaves e alicates ajustáveis, mas também algumas ferramentas especiais para fins esquisitos cujo objetivo não é imediatamente aparente e, se você não souber a maneira correta de segurá-los, eles podem facilmente cortar seu thumb (mas depois de entender como usá-los, você pode fazer coisas que são essencialmente impossíveis com as ferramentas básicas da caixa de ferramentas C #). Além disso, possui um torno, fresadora, retificadora de superfície, serra de fita para corte de metal, etc., para permitir que você projete e crie ferramentas totalmente novas sempre que sentir necessidade (mas sim, as ferramentas desses maquinistas podem e causarão ferimentos graves se você não souber o que está fazendo com eles - ou mesmo se ficar descuidado).
Isso reflete a diferença básica na filosofia: o C ++ tenta fornecer a você todas as ferramentas necessárias para essencialmente qualquer design que você queira. Ele quase não tenta controlar como você usa essas ferramentas, por isso também é fácil usá-las para produzir designs que só funcionam bem em situações raras, bem como desenhos que provavelmente são apenas uma péssima idéia e ninguém sabe de uma situação em que é provável que funcionem bem. Em particular, muito disso é feito dissociando as decisões de design - mesmo as que na prática são quase sempre acopladas. Como resultado, há uma enorme diferença entre apenas escrever C ++ e escrever bem C ++. Para escrever bem o C ++, você precisa conhecer muitos idiomas e regras práticas (incluindo regras básicas sobre a gravidade da reconsideração antes de violar outras regras básicas). Como um resultado, O C ++ é muito mais orientado à facilidade de uso (por especialistas) do que à facilidade de aprendizado. Existem também (muitas) circunstâncias em que também não é muito fácil de usar.
O C # faz muito mais para tentar forçar (ou pelo menos sugerir extremamente fortemente) o que os designers de linguagem consideraram boas práticas de design. Algumas coisas que são dissociadas em C ++ (mas geralmente andam juntas na prática) são diretamente acopladas em C #. Ele permite que o código "inseguro" ultrapasse os limites um pouco, mas honestamente, não muito.
O resultado é que, por um lado, existem vários designs que podem ser expressos diretamente diretamente em C ++ que são substancialmente mais desajeitados para serem expressos em C #. Por outro lado, é um todo muito mais fácil de aprender C #, e as chances de produzir um design realmente horrível que não vai funcionar para sua situação (ou, provavelmente, qualquer outro) são drasticamente reduzidos. Em muitos casos (provavelmente até na maioria), você pode obter um design sólido e viável simplesmente "seguindo o fluxo", por assim dizer. Ou, como um de meus amigos (pelo menos eu gosto de pensar nele como um amigo - não tenho certeza se ele realmente concorda) gosta de dizer, o C # facilita a queda no poço do sucesso.
Então, olhando mais especificamente para a questão de como class
e struct
como eles estão nas duas linguagens: objetos criados em uma hierarquia de herança, na qual você pode usar um objeto de uma classe derivada sob o disfarce de sua classe / interface base, preso ao fato de que normalmente você precisa fazer isso por meio de algum tipo de ponteiro ou referência - em um nível concreto, o que acontece é que o objeto da classe derivada contém algo de memória que pode ser tratado como uma instância da classe base / interface, e o objeto derivado é manipulado através do endereço dessa parte da memória.
Em C ++, cabe ao programador fazer isso corretamente - quando ele está usando herança, cabe a ele garantir que (por exemplo) uma função que funcione com classes polimórficas em uma hierarquia o faça por meio de um ponteiro ou referência à base classe.
Em C #, o que é fundamentalmente a mesma separação entre os tipos é muito mais explícito e imposto pelo próprio idioma. O programador não precisa executar nenhuma etapa para passar uma instância de uma classe por referência, porque isso acontecerá por padrão.
struct
nem sempre os s são armazenados na pilha; considere um objeto com umstruct
campo. Além disso, como Mason Wheeler mencionou, o problema da fatia é provavelmente o maior motivo.