Pregunta

Quiero saber que "clase base virtual" es y lo que significa.

Déjame mostrarte un ejemplo:

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

class Bar : public virtual Foo
{
public:
    void DoSpecific() { /* ... */ }
};
¿Fue útil?

Solución

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

Espero que te ayude como mini resumen.Para obtener más información, lea este y este.Un buen ejemplo también está disponible. aquí.

Otros consejos

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 llamas. D::foo(), tienes un problema de ambigüedad.Pero el real El problema surge cuando quieres usar una variable miembro de A.Por ejemplo, digamos que tenemos:

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

Cuando intentarás acceder m_iValue de D, el compilador protestará, porque en la jerarquía verá dos m_iValue, ni uno.Y si modifica uno, digamos, B::m_iValue (eso es el A::m_iValue padre de B), C::m_iValue no será modificado (ese es el A::m_iValue padre de C).

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

¿Qué puede salir mal?

Imaginar:

  • A tiene alguna característica básica.
  • B le agrega algún tipo de conjunto interesante de datos (por ejemplo)
  • C le agrega alguna característica interesante como un patrón de observador (por ejemplo, en m_iValue).
  • D hereda de B y C, y por tanto de A.

Con herencia normal, modificando m_iValue de D es ambiguo y esto debe resolverse.Incluso si lo es, hay dos m_iValues adentro D, así que será mejor que lo recuerdes y actualices los dos al mismo tiempo.

Con herencia virtual, modificando m_iValue de D esta bien...Pero...digamos que tienes D.A través de su C interfaz, adjuntó un observador.Y a través de su B interfaz, actualiza la matriz genial, que tiene el efecto secundario de cambiar directamente m_iValue...

Como el cambio de m_iValue se realiza directamente (sin utilizar un método de acceso virtual), el observador "escucha" a través C no será llamado, porque el código que implementa la escucha está en C, y B no lo sabe...

Conclusión

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

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...

Una clase base virtual es una clase que no se puede instanciar:No puede crear objeto directo a partir de él.

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.

Me gustaría sumarme a las amables aclaraciones de OJ.

La herencia virtual tiene un precio.Como ocurre con todo lo virtual, obtienes un impacto en el rendimiento.Hay una forma de evitar este problema de rendimiento que posiblemente sea menos elegante.

En lugar de romper el diamante al derivarlo virtualmente, puedes agregar otra capa al diamante, para obtener algo como esto:

   B
  / \
D11 D12
 |   |
D21 D22
 \   /
  DD

Ninguna de las clases hereda virtualmente, todas heredan públicamente.Las clases D21 y D22 ocultarán la función virtual f() que es ambigua para DD, tal vez declarando la función privada.Cada uno de ellos definiría una función contenedora, f1() y f2() respectivamente, y cada uno llamaría a f() de clase local (privada), resolviendo así los conflictos.La clase DD llama a f1() si quiere D11::f() y f2() si quiere D12::f().Si define los contenedores en línea, probablemente obtendrá cero gastos generales.

Por supuesto, si puedes cambiar D11 y D12, entonces puedes hacer el mismo truco dentro de estas clases, pero a menudo ese no es el caso.

Además de lo que ya se ha dicho sobre la herencia múltiple y virtual, hay un artículo muy interesante en el Dr. Dobb's Journal: La herencia múltiple se considera útil

Estás siendo un poco confuso.No sé si estás mezclando algunos conceptos.

No tienes una clase base virtual en tu OP.Solo tienes una clase base.

Hiciste herencia virtual.Esto generalmente se usa en herencia múltiple para que múltiples clases derivadas usen los miembros de la clase base sin reproducirlos.

No se puede crear una instancia de una clase base con una función virtual pura.esto requiere la sintaxis a la que llega Pablo.Normalmente se utiliza para que las clases derivadas deban definir esas funciones.

No quiero explicar más sobre esto porque no entiendo del todo lo que estás preguntando.

Significa que una llamada a una función virtual se reenviará a la clase "correcta".

C++ Preguntas frecuentes sencillas FTW.

En resumen, se utiliza a menudo en escenarios de herencia múltiple, donde se forma una jerarquía de "diamante".La herencia virtual romperá la ambigüedad creada en la clase inferior, cuando llama a una función en esa clase y la función debe resolverse en la clase D1 o D2 por encima de esa clase inferior.Ver el Artículo de preguntas frecuentes para un diagrama y detalles.

También se utiliza en delegación hermana, una característica poderosa (aunque no para los débiles de corazón).Ver este PREGUNTAS MÁS FRECUENTES.

Consulte también el artículo 40 en Effective C++ 3.ª edición (43 en la 2.ª edición).

Ejemplo de uso ejecutable de herencia de diamantes

Este ejemplo muestra cómo utilizar una clase base virtual en el escenario típico:para resolver la herencia de diamantes.

#include <cassert>

class A {
    public:
        A(){}
        A(int i) : i(i) {}
        int i;
        virtual int f() = 0;
        virtual int g() = 0;
        virtual int h() = 0;
};

class B : public virtual A {
    public:
        B(int j) : j(j) {}
        int j;
        virtual int f() { return this->i + this->j; }
};

class C : public virtual A {
    public:
        C(int k) : k(k) {}
        int k;
        virtual int g() { return this->i + this->k; }
};

class D : public B, public C {
    public:
        D(int i, int j, int k) : A(i), B(j), C(k) {}
        virtual int h() { return this->i + this->j + this->k; }
};

int main() {
    D d = D(1, 2, 4);
    assert(d.f() == 3);
    assert(d.g() == 5);
    assert(d.h() == 7);
}

Las clases virtuales son no Lo mismo que la herencia virtual.No se pueden crear instancias de clases virtuales, la herencia virtual es algo completamente distinto.

Wikipedia lo describe mejor que yo. http://en.wikipedia.org/wiki/Virtual_inheritance

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top