2010-01-24 19 views
19

Problema:C++ herencia virtual

class Base { 
public: 
    Base(Base* pParent); 
    /* implements basic stuff */ 
}; 

class A : virtual public Base { 
public: 
    A(A* pParent) : Base(pParent) {} 
    /* ... */ 
}; 

class B : virtual public Base { 
public: 
    B(B* pParent) : Base(pParent) {} 
    /* ... */ 
}; 

class C : public A, public B { 
public: 
    C(C* pParent) : A(pParent), B(pParent) {} // - Compilation error here 
    /* ... */ 
}; 

en la posición dada, gcc se queja de que no puede coincidir con llamada de función a Base(), es decir, el constructor predeterminado. Pero C no hereda directamente de Base, solo a través de A y B. Entonces, ¿por qué gcc se queja aquí?

Ideas? TIA /Rob

+0

compilación se realiza sin-rtti conjunto, podría ser un problema? – Robert

+6

No, la herencia es una cosa de tiempo de compilación, RTTI no será necesaria. – GManNickG

Respuesta

43

virtual Las clases base son especiales porque son inicializadas por la clase más derivada y no por ninguna clases base intermedias que heredan de la base virtual. ¿Cuál de los potenciales inicializadores múltiples sería la elección correcta para inicializar una base?

Si la clase más derivada que se está construyendo no la incluye en su lista de integración de miembros, entonces la clase base virtual se inicializa con su constructor predeterminado que debe existir y ser accesible.

Tenga en cuenta que se permite el uso de un identificador de base virtual en la lista de inicializadores de un constructor, incluso si no es una base directa de la clase en cuestión.

+0

+1, respuesta más precisa :) –

+0

Adición: Tenga en cuenta que una clase abstracta no puede inicializar su base virtual, por lo tanto, no es necesario llamar al ctor de bases virtuales en su lista de inicio de ctors, incluso si no existe un ctor predeterminado. – Deduplicator

+0

Esto significa que la inicialización de A y B de la clase principal (es decir, ': Base (pParent)') se ignoran al construir la clase más derivada? – Chris

5

Si declara un constructor personalizado, el constructor predeterminado está deshabilitado. En la herencia virtual necesita llamar directamente al constructor virtualmente heredado porque de lo contrario no sabría si inicializar por A o por B.

7

Es necesario llamar explícitamente al constructor de base de C:

class C : public A, public B { 
public: 
C(C* pParent) : Base(pParent), A(pParent), B(pParent) {} 
/*... */ 
}; 
+0

No sabía que pudieras hacer esto. ¿Esto significa que el compilador ignora el código en los códigos de 'A' y 'B' donde parecen inicializar 'Base'? – quamrana

+1

No solo _puedes hacer esto, debes_ hacerlo_. No se ignora ningún código. El constructor de 'Base' solo se llamará una vez, luego el cuerpo de los constructores para A y B, luego el cuerpo del constructor para C. – BenG

+0

Ahora entiendo el orden de las llamadas al constructor y las razones detrás de esto, excepto que Usualmente tengo una clase base con solo un constructor predeterminado, así que no tengo que tener llamadas explícitas a 'Base()'. Seguramente, en el ejemplo del OP, los compiladores aún deben ignorar la indicación de los programadores de que 'Base (pParent)' debería ser invocado directamente desde los códecs de 'A' y' B'. – quamrana

Cuestiones relacionadas