Herencia virtual
# Herencia virtual

En C++, herencia virtual es un tipo de herencia que solventa algunos de los problemas causados por la herencia múltiple (particularmente, el "problema del diamante") mediante la aclaración de la ambigüedad sobre qué miembros de clases padre usar. Es usada cuando la herencia está representando restricciones de un conjunto más que la composición de partes. Una clase base multi-heredada se denota como virtual con la palabra clave virtual.

## El problema

Considerando la siguiente jerarquía de clase.

Pero, ¿cómo Come un murciélago? Como se ha declarado arriba, una llamada a Murciélago.Come es ambiguo. Debería llamarse a Murciélago.AnimalConAlas::Come o a Murciélago.Mamífero::Come. El problema es que la semántica de la herencia múltiple convencional no modela la realidad. En un sentido, un Animal es Animal solo una vez; un Murciélago es un Mamífero y un AnimalConAlas, pero un Murciélago es tan Animal por ser Mamífero como por ser AnimalConAlas.

Esta situación es llamada a veces herencia en diamante y es un problema que la herencia virtual intenta, en parte, solventar.

## Representación de clases

Antes de seguir es útil tener en cuenta cómo se representan las clases en C++. Concretamente, la herencia es solo cuestión de poner la clase padre y la clase hija una detrás de la otra en memoria. De esta forma Murciélago es realmente (Animal, Mamífero, Animal, AnimalConAlas, Murciélago), lo que hace que se duplique Animal, causando la ambigüedad.

## Solución

Podemos redeclarar nuestras clases de la forma siguiente:

Ahora la parte Animal de Murciélago::AnimalConAlas es la misma que la usada en Murciélago::Mamífero, que es como decir que un Murciélago solo tiene un Animal en su representación y por tanto llamar a Murciélago::Come no es ambiguo.

Esto se implementa ofreciendo Mamífero y AnimalConAlas con una vtable ya que, por ejemplo, el desplazamiento de memoria entre el comienzo de un Mamífero y de su parte Animal no se conoce hasta el momento de la ejecución del programa. De esta forma Murciélago pasa a ser (vtable*, Mamífero, vtable*, AnimalConAlas, Murciélago, Animal).

Con dos punteros vtable (vtable*) por objeto, el tamaño del objeto aumenta en dos punteros, pero así solo hay un Animal y no hay ambigüedad. Hay un puntero Animal por cada herencia que hereda virtualmente de Animal: Mamífero y AnimalConAlas. Todos los objetos del tipo Murciélago tendrán los mismos vtable*, pero cada objeto Murciélago contendrá un único objeto Animal propio. Si otra clase hereda de Mamífero, como Ardilla, la vtable* en el objeto Mamífero de Ardilla será diferente del vtable* en el objeto Mamífero de un Murciélago, aunque podrían ser esencialmente el mismo en el caso especial de que la parte Ardilla del objeto tuviera el mismo tamaño que la parte Murciélago, ya que la distancia desde la parte Mamífero hasta la parte Animal sería la misma. Las vtables no son realmente las mismas, pero la información esencial en ellas (la distancia), sí lo es.

* Datos: Q1526910
