En C++, ¿qué es una clase base virtual?

Resuelto popopome asked hace 16 años • 11 respuestas

Quiero saber qué es una " clase base virtual " y qué significa.

Déjame mostrarte un ejemplo:

class Foo
{
public:
    void DoSomething() { /* ... */ }
};

class Bar : public virtual Foo
{
public:
    void DoSpecific() { /* ... */ }
};
popopome avatar Aug 22 '08 08:08 popopome
Aceptado

Las clases base virtuales, utilizadas en la herencia virtual, son una forma de evitar que aparezcan múltiples "instancias" de una clase determinada en una jerarquía de herencia cuando se utiliza la herencia múltiple.

Considere el siguiente escenario:

class A { public: void Foo() {} };
class B : public A {};
class C : public A {};
class D : public B, public C {};

La jerarquía de clases anterior da como resultado el "temido diamante" que se parece a esto:

  A
 / \
B   C
 \ /
  D

Una instancia de D estará formada por B, que incluye A, y C, que también incluye A. Entonces tienes dos "instancias" (a falta de una mejor expresión) de A.

Cuando tienes este escenario, tienes la posibilidad de ambigüedad. ¿Qué sucede cuando haces esto?

D d;
d.Foo(); // is this B's Foo() or C's Foo() ??

La herencia virtual está ahí para resolver este problema. Cuando especifica virtual al heredar sus clases, le está diciendo al compilador que solo desea una instancia única.

class A { public: void Foo() {} };
class B : public virtual A {};
class C : public virtual A {};
class D : public B, public C {};

Esto significa que sólo hay una "instancia" de A incluida en la jerarquía. Por eso

D d;
d.Foo(); // no longer ambiguous

Este es un mini resumen. Para obtener más información, lea esto y esto . Un buen ejemplo también está disponible aquí .

OJ. avatar Aug 22 '2008 01:08 OJ.

Acerca del diseño de la memoria

Como nota al margen, el problema con el Dreaded Diamond es que la clase base está presente varias veces. Entonces, con la herencia regular, crees que tienes:

  A
 / \
B   C
 \ /
  D

Pero en el diseño de la memoria, tienes:

A   A
|   |
B   C
 \ /
  D

Esto explica por qué cuando llama D::foo(), tiene un problema de ambigüedad. Pero el verdadero problema surge cuando quieres utilizar un miembro de datos de A. Por ejemplo, digamos que tenemos:

class A
{
    public :
       foo() ;
       int m_iValue ;
} ;

Cuando intente acceder m_iValuedesde D, el compilador protestará, porque en la jerarquía verá dos m_iValue, no uno. Y si modifica uno, digamos, B::m_iValue(que es el A::m_iValuepadre de B), C::m_iValueno se modificará (que es el A::m_iValuepadre de C).

Aquí es donde la herencia virtual resulta útil, ya que con ella volverá a un verdadero diseño de diamante, no solo con un foo()método, sino también con uno y solo uno m_iValue.

¿Qué puede salir mal?

Imaginar:

  • Atiene alguna característica básica.
  • Ble agrega algún tipo de conjunto interesante de datos (por ejemplo)
  • Cle agrega alguna característica interesante como un patrón de observador (por ejemplo, en m_iValue).
  • Dhereda de By C, y por tanto de A.

Con herencia normal, modificar m_iValuedesde Des ambiguo y esto debe resolverse. Incluso si lo es, hay dos m_iValuesdentro D, así que será mejor que lo recuerdes y actualices los dos al mismo tiempo.

Con la herencia virtual, modificar m_iValuedesde Destá bien... Pero... Digamos que tienes D. A través de su Cinterfaz, adjuntó un observador. Y a través de su Binterfaz, actualizas la genial matriz, que tiene el efecto secundario de cambiar directamente m_iValue...

Como el cambio se realiza directamente (sin utilizar un método de acceso virtual), no se llamará m_iValueal observador que "escucha" porque el código que implementa la escucha está en y no lo sabe...CCB

Conclusión

Si tienes un diamante en tu jerarquía, significa que tienes un 95% de probabilidad de haber hecho algo mal con dicha jerarquía.

paercebal avatar Sep 21 '2008 23:09 paercebal

Explicar la herencia múltiple con bases virtuales requiere conocimientos del modelo de objetos de C++. Y es mejor explicar el tema con claridad en un artículo y no en un cuadro de comentarios.

La mejor explicación legible que encontré y que resolvió todas mis dudas sobre este tema fue este artículo: http://www.phpcompiler.org/articles/virtualinheritance.html

Realmente no necesitarás leer nada más sobre el tema (a menos que seas un escritor compilador) después de leer eso...

lenkite avatar Jun 13 '2009 22:06 lenkite

Una clase base virtual es una clase de la que no se pueden crear instancias: no se puede crear un objeto directo a partir de ella.

Creo que estás confundiendo dos cosas muy diferentes. La herencia virtual no es lo mismo que una clase abstracta. La herencia virtual modifica el comportamiento de las llamadas a funciones; a veces resuelve llamadas a funciones que de otro modo serían ambiguas, a veces difiere el manejo de llamadas a funciones a una clase distinta a la que uno esperaría en una herencia no virtual.

wilhelmtell avatar Aug 22 '2008 01:08 wilhelmtell