resueltos programacion poo orientada objetos libro ejercicios ejemplo constructores codigo clases abstractas c++ inheritance constructor multiple-inheritance virtual-inheritance

c++ - programacion - Mezcla de herencia virtual y no virtual de una clase base



objetos en c++ (3)

Este es el código:

struct Biology { Biology() { cout << "Biology CTOR" << endl; } }; struct Human : Biology { Human() { cout << "Human CTOR" << endl; } }; struct Animal : virtual Biology { Animal() { cout << "Animal CTOR" << endl; } }; struct Centaur : Human, Animal { Centaur() { cout << "Centaur CTOR" << endl; } }; int main() { Centaur c; return 0; }

Este código imprime:

Biology CTOR Biology CTOR Human CTOR Animal CTOR Centaur CTOR

¿Por qué?

Ya que creamos un objeto Centaur , comenzamos a construir el Centaur construyendo Human , Animal y finalmente Centaur (comenzamos desde lo menos derivado hasta lo más derivado).

Empecemos por Human : Human hereda de Biology , por lo que llamamos primero al constructor de Biology . Ahora que Human clase base del Human está construida, finalmente podemos construir al Human mismo. Pero en cambio, ¡la Biology se construye de nuevo!

¿Por qué? ¿Qué está pasando detrás de las escenas?

Tenga en cuenta que fue completamente intencional dejar a Animal heredado virtualmente de la Biology y, al mismo tiempo, también fue intencional dejar al Human no virtualmente heredado de la Biology .

Estamos resolviendo el Dreaded Diamond de una manera incorrecta: tanto el humano como el animal deben heredar virtualmente la biología para que esto funcione.

Tengo curiosidad.

También, vea este código:

struct Biology { Biology() { cout << "Biology CTOR" << endl; } }; struct Human : virtual Biology { Human() { cout << "Human CTOR" << endl; } }; struct Animal : Biology { Animal() { cout << "Animal CTOR" << endl; } }; struct Centaur : Human, Animal { Centaur() { cout << "Centaur CTOR" << endl; } }; int main() { Centaur c; return 0; }

Aquí tenemos Human herencia Human virtualmente de la Biology , mientras que el Animal va a heredar de la "manera clásica".

Pero esta vez, la salida es diferente:

Biology CTOR Human CTOR Biology CTOR Animal CTOR Centaur CTOR

Esto se debe a que Centaur hereda primero de Human y luego de Animal .

Si el orden hubiera sido el inverso, habríamos logrado el mismo resultado que antes, en el primer ejemplo: dos instancias de Biology construidas en una fila.

¿Cuál es la lógica de esto?

Por favor, trate de explicar su camino, ya he revisado toneladas de sitios web que hablan sobre esto. Pero ninguno parece satisfacer mi petición.


  1. Todas las clases base que heredan virtualmente de la Biology comparten una instancia de la base de Biology entre ellas.
  2. Todas las clases base que heredan no virtualmente de la Biology tienen una instancia de cada Biology .

Tiene una base en cada categoría, por lo tanto, tiene una instancia de Biology presentada por Human (y en principio compartida con otras) y una instancia presentada por Animal (nunca compartida con ninguna otra clase base).


Está claro a partir de la salida que se crea una instancia de dos objetos de Biology . Eso es porque solo has hecho una herencia virtual . Dos instancias de clase base son la causa de la ambigüedad en el temido problema de los diamantes y la solución es hacer (como sabemos) ambas herencias de la Biology virtual .

Resumen de la jerarquía:

Biology Biology | | # one and only one inheritance virtual Human Animal / / Centaur

Ok, leamos la salida nuevamente con estas reglas en mente:

  • Las clases base se construyen antes que las clases derivadas.
  • Las clases base se construyen en el orden en que aparecen en la lista-especificador base .
  • Las clases base virtuales se construyen antes que las no virtuales por la clase más derivada , vea esto .

1ra salida - Animal virtual ly hereda de la Biology :

Biology CTOR # virtual base class inherited from Animal Biology CTOR # non-virtual base class of Human Human CTOR # Human itself Animal CTOR # Animal''s virtual base class already constructed Centaur CTOR

2da salida - Human virtual ly hereda de la Biology :

Biology CTOR # virtual base class inherited from Human Human CTOR # Human''s virtual base class already constructed Biology CTOR # non-virtual base class of Animal Animal CTOR # Animal itself Centaur CTOR

Párrafo estándar más informativo ( [class.base.init]/10 ) :

En un constructor no delegante, la inicialización se realiza en el siguiente orden:

- Primero, y solo para el constructor de la clase más derivada (1.8), las clases de base virtual se inicializan en el orden en que aparecen en el primer recorrido de izquierda a derecha del gráfico acíclico dirigido de clases de base, donde "izquierda -a-derecha ”es el orden de aparición de las clases base en la lista derivada -especificador-base de la clase.

- Luego, las clases base directas se inicializan en orden de declaración tal como aparecen en la lista de especificadores de base (independientemente del orden de los inicializadores de memoria ).

...


La herencia no virtual es una relación exclusiva, como la membresía. Una clase puede ser la clase base no virtual de otra clase en un objeto completo dado.

Esto implica que una clase puede anular las funciones virtuales de una clase base no virtual sin causar conflictos o problemas.

Un constructor también puede inicializar bases no virtuales de manera confiable.

Solo las bases virtuales pueden ser clases de base directa de muchas bases indirectas de un objeto completo. Debido a que una clase base virtual se puede compartir, los anuladores pueden entrar en conflicto.

Un constructor puede intentar inicializar un subobjeto de base virtual en ctor-init-list, pero si la clase se deriva aún más, esa parte de ctor-init-list se ignorará.