Estoy confundido sobre cuáles podrían ser los problemas si un constructor fuera heredado de una clase base. Cpp Primer Plus dice:
Los constructores son diferentes de otros métodos de clase en que crean nuevos objetos, mientras que otros métodos son invocados por objetos existentes . Esta es una razón por la que los constructores no se heredan . La herencia significa que un objeto derivado puede usar un método de clase base, pero, en el caso de los constructores, el objeto no existe hasta después de que el constructor haya hecho su trabajo.
Entiendo que se llama al constructor antes de que se complete la construcción del objeto.
¿Cómo puede conducir a problemas si una clase secundaria hereda ( al heredar quiero decir que la clase secundaria puede anular el método de la clase primaria, etc. No solo acceder al método de la clase primaria ) el constructor primario?
Entiendo que no hay necesidad de llamar explícitamente a un constructor dentro de un código [no que yo sepa todavía.] Excepto al crear objetos. Incluso entonces puede hacerlo utilizando algún mecanismo para invocar el constructor principal [En cpp, usando ::
o usando member initialiser list
, En java usando super
]. En Java hay una aplicación para llamarlo en la primera línea, entiendo que es para asegurarse de que el objeto primario se crea primero y luego continúa la construcción del objeto secundario.
Puede anularlo . Pero no puedo encontrar situaciones en las que esto pueda plantear un problema. Si el hijo hereda el constructor principal, ¿qué puede salir mal?
Entonces, esto es solo para evitar heredar funciones innecesarias. ¿O hay más?
fuente
Respuestas:
No puede haber una herencia adecuada de constructores en C ++, porque el constructor de una clase derivada necesita realizar acciones adicionales que un constructor de clase base no tiene que hacer y no conoce. Estas acciones adicionales son la inicialización de los miembros de datos de la clase derivada (y, en una implementación típica, también configuran el vpointer para que haga referencia a las clases derivadas vtable).
Cuando se construye una clase, hay una serie de cosas que siempre deben suceder: los constructores de la clase base (si los hay) y los miembros directos necesitan ser llamados y si hay alguna función virtual, el vpointer debe estar configurado correctamente . Si usted no proporciona un constructor para su clase, el compilador será crear uno que lleva a cabo las acciones necesarias y nada más. Si haces proporcionar un constructor, pero se pierda en algunas de las acciones requeridas (por ejemplo, la inicialización de algunos miembros), entonces el compilador añadirá automáticamente las acciones que faltan a su constructor. De esta manera, el compilador asegura que cada clase tenga al menos un constructor y que cada constructor inicialice completamente los objetos que crea.
En C ++ 11, se ha introducido una forma de 'herencia de constructor' donde puede indicarle al compilador que genere un conjunto de constructores para usted que tome los mismos argumentos que los constructores de la clase base y que simplemente envíe esos argumentos a clase base
Aunque oficialmente se llama herencia, no lo es realmente porque todavía hay una función específica de clase derivada. Ahora solo lo genera el compilador en lugar de ser escrito explícitamente por usted.
Esta característica funciona así:
Derived
ahora tiene dos constructores (sin contar los constructores copiar / mover). Uno que toma un int y una cadena y otro que toma solo un int.fuente
m()
viene y cómo cambiaría si su tipo fuera, por ejemploint
.using Base::Base
implícitamente? Tendría grandes consecuencias si olvidara esa línea en una clase derivada y necesito heredar el constructor en todas las clases derivadasNo está claro qué quiere decir con "heredar el constructor principal". Utiliza la palabra anulación , lo que sugiere que puede estar pensando en constructores que se comportan como funciones virtuales polimórficas . Deliberadamente, no uso el término "constructores virtuales" porque ese es un nombre común para un patrón de código en el que realmente se requiere una instancia ya existente de un objeto para crear otro.
Hay poca utilidad para los constructores polimórficos fuera del patrón de "constructor virtual", y es difícil encontrar un escenario concreto en el que se pueda usar un constructor polimórfico real. Un ejemplo muy ingenioso que de ninguna manera es incluso C ++ remotamente válido :
En este caso, el constructor llamado depende del tipo concreto de la variable que se construye o asigna. Es complejo de detectar durante la generación de análisis / código y no tiene utilidad: conoce el tipo concreto que está construyendo y ha escrito un constructor específico para la clase derivada. El siguiente código válido de C ++ hace exactamente lo mismo, es un poco más corto y es más explícito en lo que hace:
Una segunda interpretación o quizás una pregunta adicional es: ¿qué pasaría si los constructores de la clase Base estuvieran presentes automáticamente en todas las clases derivadas a menos que se ocultaran explícitamente?
Tendría que escribir código adicional para ocultar un constructor principal que sea incorrecto para construir la clase derivada. Esto puede suceder cuando la clase derivada especializa la clase base de tal manera que ciertos parámetros se vuelven irrelevantes.
El ejemplo típico es rectángulos y cuadrados (tenga en cuenta que los cuadrados y rectángulos generalmente no son sustituibles por Liskov, por lo que no es un diseño muy bueno, pero resalta el problema).
Si Square heredó el constructor de dos valores de Rectangle, podría construir cuadrados con una altura y ancho diferentes ... Eso es lógicamente incorrecto, por lo que querrá ocultar ese constructor.
fuente
Por qué no se heredan los constructores: la respuesta es sorprendentemente simple: el constructor de la clase base "construye" la clase base y el constructor de la clase heredada "construye" la clase heredada. Si la clase heredada heredaría el constructor, el constructor intentaría construir un objeto de tipo de clase base y usted no podría "construir" un objeto de tipo de clase heredada.
Qué tipo de derrota el propósito de inherente a una clase.
fuente
El problema más obvio al permitir que la clase derivada anule el constructor de la clase base es que el desarrollador de la clase derivada ahora es responsable de saber cómo construir su (s) clase (s) base (s). ¿Qué sucede cuando la clase derivada no construye la clase base correctamente?
Además, el principio de sustitución de Liskov ya no se aplicaría, ya que no puede contar con que su colección de objetos de clase base sea compatible entre sí, porque no hay garantía de que la clase base se haya construido de manera adecuada o compatible con los otros tipos derivados.
Se complica aún más cuando se agrega más de 1 nivel de herencia. Ahora su clase derivada necesita saber cómo construir todas las clases base en la cadena.
Entonces, ¿qué sucede si agrega una nueva clase base a la parte superior de la jerarquía de herencia? Tendría que actualizar todos los constructores de clase derivados.
fuente
Los constructores son fundamentalmente diferentes de otros métodos:
Entonces, ¿por qué no se heredan? Respuesta simple: porque siempre hay una anulación, ya sea generada o escrita manualmente.
¿Por qué cada clase necesita un constructor? Esa es una pregunta complicada y creo que la respuesta depende del compilador. Existe un constructor "trivial" para el que el compilador no exige que se llame como parece. Creo que eso es lo más parecido a lo que quiere decir con herencia, pero por las tres razones mencionadas anteriormente, creo que comparar constructores con métodos normales no es realmente útil. :)
fuente
Cada clase necesita un constructor, incluso los predeterminados.
C ++ creará constructores predeterminados para usted, excepto si crea un constructor especializado.
En caso de que su clase base use un constructor especializado, deberá escribir el constructor especializado en la clase derivada incluso si ambos son iguales y encadenarlos.
C ++ 11 le permite evitar la duplicación de código en constructores usando :
Un conjunto de constructores heredados se compone de
Todos los constructores heredados que no son el constructor predeterminado o el constructor copiar / mover y cuyas firmas no coinciden con los constructores definidos por el usuario en la clase derivada, se declaran implícitamente en la clase derivada. Los parámetros predeterminados no se heredan
fuente
Puedes usar:
¿Estás preguntando por qué tienes que hacer esto?
La subclase podría tener propiedades adicionales que podrían necesitar inicializarse en el constructor, o podría inicializar las variables de la clase base de una manera diferente.
¿De qué otra forma crearías el objeto de subtipo?
fuente