2010-10-21 34 views
18

Tengo una pregunta sobre la inicialización de miembros heredados en el constructor de la clase derivada. Código de ejemplo:C++: Inicialización del campo heredado

class A 
    { 
public: 
    int m_int; 
    }; 

class B: public A 
    { 
public: 
    B():m_int(0){} 
    }; 

Este código me da el siguiente resultado:

In constructor 'B::B()': Line 10: error: class 'B' does not have any field named 'm_int'

(ver http://codepad.org/tn1weFFP)

estoy adivinando por qué sucede esto? m_int debe ser miembro de B, y la clase primaria A ya debe inicializarse cuando se produce la inicialización de m_int en B (porque los constructores principales se ejecutan antes de la inicialización del miembro de la clase heredada). ¿Dónde hay un error en mi razonamiento? ¿Qué sucede realmente en este código?

EDIT: Soy consciente de otras posibilidades para inicializar este miembro (constructor base o asignación en el constructor derivado), pero quiero entender por qué es ilegal en la forma en que lo intento? ¿Algun característica específica del lenguaje C++ o tal? Por favor apúntame a un párrafo en C++ estándar si es posible.

Respuesta

18

Necesitas hacer un constructor de A (que puede estar protegido por lo que sólo B puede llamar), que m_int inicializa igual que usted tiene, entonces invocar :A(0) donde tiene :m_int(0)

También puedes, simplemente establecer m_int = 0 en el cuerpo del constructor de B Es accesible (como usted describe) simplemente no está disponible en la sintaxis especial del constructor.

+5

Esta es una buena respuesta, pero me gustaría añadir algunas explicaciones. Cuando usa el operador: le dice al compilador que antes de hacer cualquier otra cosa debería ejecutar estas instrucciones. Básicamente está estableciendo una variable antes de que se haya ejecutado el constructor padre (o cualquier otra cosa). Por lo tanto, la variable no existe. : A(), m_int (0) debería funcionar también.De manera predeterminada, si no usa:, el compilador ejecutará el constructor de las clases base. En otras palabras, si no hace nada, C++ hará las cosas predeterminadas por usted, si comienza a especificar las cosas, asume que sabe lo que está haciendo. –

+0

Hmmm ... Hasta donde yo sé, el constructor de la clase padre siempre se ejecuta antes que cualquier otra inicialización, por lo que la variable 'm_int' ya existe cuando intento inicializarla. Así que este no debería ser el problema ... – Haspemulator

+0

@Haspemulator Sí, ya existe pero es por eso que está obteniendo el error. Ya ha sido inicializado por defecto por el constructor de A. No puede reinicializar una variable en el constructor de B. Puede reasignar como dice Ben Jackson arriba ('m_int = 0') y eso es todo en ese punto. – wheaties

4

Lo que quiere decir esto:

class A{ 
public: 
    A() : m_int(0); 
    int m_int; 
}; 

modo que m_int se inicializa en el lugar correcto.

Editar:

Desde un comentario anterior, la razón por la que el compilador se queja cuando intenta inicializar la variable m_int en B es que ya se ha inicializado por el constructor de A. Es decir, no puede reinicializar algo, solo reasignar. Por lo tanto, puede reasignar como mencionó Ben Jackson anteriormente o puede iniciar en el lugar adecuado.

4

Para construir una instancia de la clase B primero crea una instancia de la clase A. Durante esa instanciación se inicializa m_int. Es después de esa inicialización que se llama al constructor b, por lo que no puede reiniciar el m_int. Si ese es su objetivo, entonces puede implementar un constructor para A que toma un int y luego llamar a que en la lista de inicialización B 's:

class A 
{ 
public: 
    A(int x): m_int(x) {} 
    int m_int; 
}; 

class B: public A 
{ 
public: 
    B(): A(2) {} 
}; 
+0

¿Hay alguna razón por la cual no está disponible en la lista de inicialización? Soy consciente de otras posibilidades para inicializar este miembro (constructor base o asignación en el constructor derivado), pero quiero entender por qué es ilegal en la forma en que lo intento. ¿Algun característica específica del lenguaje C++ o tal? Por favor apúntame a un párrafo en C++ estándar si es posible. – Haspemulator

+0

Son dos cosas: las clases derivadas instancian sus clases base primero, y los miembros se inicializan en el orden en que se declaran, no el orden en que aparecen en la lista de inicialización. Por lo tanto, los miembros de la base se inicializan primero y no puede reinicializarlos. –

0

crea un constructor en A y el uso B(): A (2) {} insteed de B(): m_int (0) {} funciona.