web-dev-qa-db-fra.com

l'initialiseur de membre ne nomme pas un membre de données non statique ou une classe de base

J'ai du mal à trouver des hits sur google pour cela.

struct a {
    float m_x;
    float m_z;
public:
    a(float x): m_x(x) {}
};

class b : public a {
    b(float z): m_z(z) {}
};

Sur clang 3.2:

error: member initializer 'm_z' does not name a non-static data member or base class
    b(float z): m_z(z) {}
34
Steven Lu

Non, vous ne pouvez pas initialiser directement les membres de la classe de base à partir de la liste des initialiseurs. En effet, l'ordre d'initialisation se déroule de cette manière

Norme C++ n3337 § 12.6.2/10

Dans un constructeur non délégué, l'initialisation se déroule dans l'ordre suivant:

- Premièrement, et uniquement pour le constructeur de la classe la plus dérivée (1.8), les classes de base virtuelles sont initialisées dans l'ordre dans lequel elles apparaissent sur une profondeur de gauche à droite du graphe acyclique dirigé des classes de base, où "gauche -to-right "est l'ordre d'apparition des classes de base dans la liste dérivée des spécificateurs de base des classes.

- Ensuite, les classes de base directes sont initialisées dans l'ordre de déclaration telles qu'elles apparaissent dans la liste des spécificateurs de base (quel que soit l'ordre des initialiseurs mem) .

- Ensuite, les membres de données non statiques sont initialisés dans l'ordre dans lequel ils ont été déclarés dans la définition de classe (là encore, quel que soit l'ordre des initialiseurs mem) .

- Enfin, l'instruction composée du corps constructeur est exécutée .

[Remarque: l'ordre de déclaration est mandaté pour garantir que les sous-objets de base et de membre sont détruits dans l'ordre inverse de l'initialisation. - note de fin]

Vous pouvez donc spécifier un constructeur dans une classe de base (il peut être protégé) et l'utiliser dans la liste d'initialisation de la classe dérivée ( devrait être préféré ) ou vous pouvez assigner = à un membre de classe de base dans un corps de classe dérivé (comportement différent, effet différent et également moins efficace - vous affectez au membre initialisé par défaut (a déjà une valeur)).

Dans le premier cas, vous pourriez l'écrire de cette façon:

struct A {
    float m_x;
    float m_z;
    A(){}
protected:
    A(float x): m_x(x) {}
};

class B : public A {
public:
    B(float z) : A(z) {}
    // alternatively
    // B(float z) {
    //     m_x = z;
    // }
};

int main(){
    B b(1);
    return 0;
}
41
4pie0