2010-10-21 20 views
18

J'ai une question sur l'initialisation des membres hérités dans le constructeur de la classe dérivée. Exemple de code:C++: Initialisation du champ hérité

class A 
    { 
public: 
    int m_int; 
    }; 

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

Ce code me donne le résultat suivant:

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

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

Je devine pourquoi cela se produit? m_int doit être membre de B, et la classe parente A doit déjà être initialisée lorsque l'initialisation de m_int dans B se produit (car les constructeurs parents s'exécutent avant l'initialisation de membre de la classe héritée). Où est une erreur dans mon raisonnement? Que se passe-t-il vraiment dans ce code?

EDIT: Je suis conscient d'autres possibilités pour initialiser ce membre (constructeur de base ou affectation dans le constructeur dérivé), mais je veux comprendre pourquoi est-ce illégal dans la façon dont je l'essaie? Une fonctionnalité spécifique du langage C++ ou autre? S'il vous plaît pointez-moi vers un paragraphe en C++ standard si possible.

Répondre

18

Vous devez faire un constructeur A (il peut être protégé de façon que B peut l'appeler) initialisant m_int comme vous l'avez, vous appeler :A(0) où vous avez :m_int(0)

Vous pouvez aussi simplement mettre m_int = 0 dans le corps du constructeur de B Il est accessible (comme vous le décrivez) il n'est tout simplement pas disponible dans la syntaxe du constructeur spécial.

+5

C'est une bonne réponse, mais je voudrais juste ajouter quelques explications. Lorsque vous utilisez l'opérateur:, vous dites au compilateur qu'avant de faire quoi que ce soit d'autre, il doit exécuter ces instructions. Fondamentalement, vous définissez une variable avant l'exécution du constructeur parent (ou de tout autre élément). Par conséquent, la variable n'existe pas. : A(), m_int (0) devrait aussi fonctionner.Par défaut, si vous n'utilisez pas:, le compilateur exécutera le constructeur des classes de base. En d'autres termes, si vous ne faites rien C++ fera des choses par défaut pour vous, si vous commencez à spécifier des choses, cela suppose que vous sachiez ce que vous faites. –

+0

Hmmm ... Autant que je sache, le constructeur de la classe parent est toujours exécuté avant toute autre initialisation, et donc la variable 'm_int' existe déjà lorsque j'essaie de l'initialiser. Donc ça ne devrait pas être le problème ... – Haspemulator

+0

@Haspemulator Oui, ça existe déjà mais c'est pour ça que tu as l'erreur. Il a déjà été initialisé par défaut par le constructeur de A. Vous ne pouvez pas réinitialiser une variable dans le constructeur de B. Vous pouvez réaffecter comme l'indique Ben Jackson ci-dessus ('m_int = 0') et c'est à peu près tout. – wheaties

4

Ce que vous voulez est ceci:

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

de sorte que m_int est initialisé au bon endroit.

Edit:

D'un commentaire ci-dessus, la raison pour laquelle le compilateur se plaint lorsque vous essayez d'initialiser la variable m_int dans B est qu'il a déjà été initialisé par le constructeur de A. Autrement dit, vous ne pouvez pas réinitialiser quelque chose, seulement réaffecter. Ainsi, vous pouvez réaffecter comme Ben Jackson indiqué ci-dessus ou vous pouvez initialiser à l'endroit approprié.

4

Pour construire une instance de classe B, vous devez d'abord instancier une instance de classe A. Pendant cette instanciation, m_int est initialisé. C'est après cette initialisation que le constructeur de b est appelé, donc vous ne pouvez pas réinitialiser m_int. Si tel est votre objectif, vous pouvez mettre en œuvre un constructeur de A qui prend un entier, puis appelez que dans la liste d'initialisation de B:

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

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

Y at-il une raison pour laquelle il n'est pas disponible dans la liste d'initialisation? Je connais d'autres possibilités pour initialiser ce membre (constructeur de base ou affectation dans le constructeur dérivé), mais je veux comprendre pourquoi est-ce illégal dans la façon dont j'essaie? Une fonctionnalité spécifique du langage C++ ou autre? S'il vous plaît pointez-moi vers un paragraphe en C++ standard si possible. – Haspemulator

+0

C'est deux choses - les classes dérivées instancient d'abord leurs classes de base, et les membres sont initialisés dans l'ordre où ils sont déclarés, et non dans l'ordre dans lequel ils apparaissent dans la liste d'initialisation. Par conséquent, les membres de la base sont initialisés en premier et vous ne pouvez pas les réinitialiser. –

0

faire un constructeur dans un et l'utilisation B(): A (2) {} inséré de B(): m_int (0) {} son fonctionnement.