Por analogía, C # es básicamente como un conjunto de herramientas mecánicas en las que alguien ha leído que generalmente se deben evitar los alicates y las llaves ajustables, por lo que no incluye las llaves ajustables, y los alicates están bloqueados en un cajón especial marcado "inseguro", y solo se puede usar con la aprobación de un supervisor, después de firmar un descargo de responsabilidad que exime a su empleador de cualquier responsabilidad por su salud.
C ++, en comparación, no solo incluye llaves ajustables y alicates, sino también algunas herramientas de uso especial más bien extrañas cuyo propósito no es aparente de inmediato, y si no conoce la forma correcta de sostenerlas, podrían fácilmente corta el pulgar (pero una vez que entiendas cómo usarlos, puedes hacer cosas que son esencialmente imposibles con las herramientas básicas en la caja de herramientas de C #). Además, tiene un torno, una fresadora, una amoladora de superficie, una sierra de cinta para cortar metales, etc., para permitirle diseñar y crear herramientas completamente nuevas cada vez que sienta la necesidad (pero sí, esas herramientas de maquinista pueden y causarán lesiones graves si no sabes lo que estás haciendo con ellos, o incluso si simplemente te descuidas).
Eso refleja la diferencia básica en filosofía: C ++ intenta proporcionarle todas las herramientas que pueda necesitar para prácticamente cualquier diseño que desee. Casi no intenta controlar cómo usa esas herramientas, por lo que también es fácil usarlas para producir diseños que solo funcionan bien en situaciones raras, así como diseños que probablemente son solo una mala idea y nadie sabe de una situación en la que Es probable que funcionen bien. En particular, gran parte de esto se hace al desacoplar las decisiones de diseño, incluso aquellas que en la práctica realmente casi siempre están acopladas. Como resultado, hay una gran diferencia entre solo escribir C ++ y escribir bien C ++. Para escribir bien en C ++, necesitas conocer muchos modismos y reglas generales (incluidas las reglas básicas sobre cómo considerar seriamente antes de romper otras reglas básicas). Como resultado, C ++ se orienta mucho más hacia la facilidad de uso (por parte de expertos) que a la facilidad de aprendizaje. También hay (demasiadas) circunstancias en las que tampoco es realmente fácil de usar.
C # hace mucho más para intentar forzar (o al menos extremadamente sugiere) lo que los diseñadores de idiomas consideraron buenas prácticas de diseño. Algunas cosas que están desacopladas en C ++ (pero generalmente van juntas en la práctica) están directamente acopladas en C #. Permite que el código "inseguro" empuje los límites un poco, pero honestamente, no mucho.
El resultado es que, por un lado, hay bastantes diseños que pueden expresarse bastante directamente en C ++ que son mucho más torpes de expresar en C #. Por otro lado, es mucho más fácil aprender C # entero , y las posibilidades de producir un diseño realmente horrible que no funcione para su situación (o probablemente cualquier otro) son drásticamente reducido. En muchos casos (probablemente incluso en la mayoría), puede obtener un diseño sólido y funcional simplemente "siguiendo el flujo", por así decirlo. O, como a uno de mis amigos (al menos me gusta verlo como un amigo, no estoy seguro de si realmente está de acuerdo) le gusta decirlo, C # hace que sea fácil caer en el pozo del éxito.
Por lo tanto, analizando más específicamente la pregunta de cómo class
y struct
entendieron cómo están en los dos idiomas: objetos creados en una jerarquía de herencia donde se podría usar un objeto de una clase derivada en la forma de su base clase / interfaz, está bastante atascado con el hecho de que normalmente necesita hacerlo a través de algún tipo de puntero o referencia; en un nivel concreto, lo que sucede es que el objeto de la clase derivada contiene algo de memoria que puede ser se trata como una instancia de la clase / interfaz base, y el objeto derivado se manipula a través de la dirección de esa parte de la memoria.
En C ++, depende del programador hacerlo correctamente: cuando usa la herencia, depende de él asegurarse de que (por ejemplo) una función que funciona con clases polimórficas en una jerarquía lo haga a través de un puntero o referencia a la clase base.
En C #, lo que es fundamentalmente la misma separación entre los tipos es mucho más explícito, y lo impone el propio lenguaje. El programador no necesita tomar ningún paso para pasar una instancia de una clase por referencia, porque eso sucederá por defecto.