Por analogia, o C # é basicamente como um conjunto de ferramentas mecânicas onde alguém leu que você geralmente deve evitar alicates e chaves ajustáveis, por isso não inclui chaves ajustáveis, e os alicates são travados em uma gaveta especial marcada. "inseguro" e só pode ser usado com a aprovação de um supervisor, após assinar um aviso de isenção que isenta seu empregador de qualquer responsabilidade por sua saúde.
O C ++, por comparação, não inclui apenas alicates ajustáveis e alicates, mas ferramentas especiais para fins especiais, cuja finalidade não é imediatamente aparente, e se você não sabe o jeito certo de segurá-las, elas podem facilmente corte o polegar (mas, depois de entender como usá-los, 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 mecânico, fresadora, retificadora de superfície, serra de fita para corte de metal, etc., para permitir que você crie e crie ferramentas totalmente novas sempre que sentir necessidade (mas, sim, essas ferramentas podem e ferimentos graves, se você não sabe o que está fazendo com eles - ou até mesmo se você ficar descuidado).
Isso reflete a diferença básica na filosofia: o C ++ tenta fornecer todas as ferramentas que você pode precisar para qualquer projeto que você queira. Não faz quase nenhuma tentativa de 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, assim como projetos que provavelmente são apenas uma péssima ideia e ninguém sabe de uma situação em que Eles provavelmente trabalharão bem. Em particular, muito disso é feito através do desacoplamento de decisões de projeto - mesmo aquelas que na prática são quase sempre acopladas. Como resultado, há uma enorme diferença entre escrever C ++ e escrever C ++. Para escrever C ++ bem, você precisa conhecer muitas expressões idiomáticas e regras práticas (incluindo regras gerais sobre a seriedade de reconsiderar antes de quebrar outras regras básicas). Como resultado, o C ++ é muito mais orientado para a facilidade de uso (por especialistas) do que a facilidade de aprendizado. Há também (todas as demais) circunstâncias em que não é realmente muito fácil de usar também.
O C # faz muito mais para tentar forçar (ou pelo menos extremamente sugerir strongmente) o que os projetistas de linguagem consideravam boas práticas de projeto. Algumas coisas que são desacopladas em C ++ (mas geralmente juntas na prática) são diretamente acopladas em C #. Ele permite que o código "inseguro" empurre os limites um pouco, mas honestamente, não muito.
O resultado é que, por um lado, existem alguns designs que podem ser expressos de forma bastante direta em C ++, que são substancialmente mais desajeitados para serem expressos em C #. Por outro lado, é muito mais fácil aprender C #, e as chances de produzir um design realmente horrível que não funcione para sua situação (ou provavelmente qualquer outra) são drasticamente < Reduzido. Em muitos (provavelmente até a maioria) casos, você pode obter um design sólido e funcional simplesmente "indo com o fluxo", por assim dizer. Ou, como um dos meus amigos (pelo menos eu gosto de pensar nele como um amigo - não tenho certeza se ele realmente concorda) gosta de colocá-lo, o C # torna fácil cair no poço do sucesso.
Então, olhando mais especificamente para a questão de como class
e struct
tem como estão nas duas linguagens: objetos criados em uma hierarquia de herança onde você pode usar um objeto de uma classe derivada na forma de sua base classe / interface, você está praticamente preso ao fato de que normalmente 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 alguma memória que pode ser tratado como uma instância da classe / interface base, 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 trabalhe com classes polimórficas em uma hierarquia o faça através de um ponteiro ou referência. para a classe base.
Em C #, o que é fundamentalmente a mesma separação entre os tipos é muito mais explícito e aplicado pela própria linguagem. O programador não precisa tomar nenhuma medida para passar uma instância de uma classe por referência, porque isso acontecerá por padrão.