member initializer does not name a non-static data member or base class

70,448

No you cannot initialize base class members from initializer list directly. This is because order of initialization proceeds in this way

C++ Standard n3337 § 12.6.2/10

In a non-delegating constructor, initialization proceeds in the following order:

— First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

Finally, the compound-statement of the constructor body is executed.

[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. — end note ]

So you can specify a constructor in a base class (it can be protected) and use that one in initialization list of derived class (should be preferred) or you can assign to a base class member in derived class ctor body (different behaviour, different effect and also less efficient - you are assigning to default initialized (already has value) member).

In the former case you might write it this way:

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;
}
Share:
70,448

Related videos on Youtube

Steven Lu
Author by

Steven Lu

Play a multitouch HTML5 Tetris clone -- http://htmltetris.com (Interesting note about this site. It used to be my site, then Tetris Co. sent me a cease and desist, then I forgot about it, and now it’s back: someone brought it back and put MY code back on the site.) A huge fan of tmux and vim.

Updated on October 28, 2020

Comments

  • Steven Lu
    Steven Lu over 3 years

    I'm having a hard time finding hits on google for this.

    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) {}
    };
    

    On 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) {}
    
    • Steven Lu
      Steven Lu over 10 years
      Why? I haven't made an "evil inheritance diamond" yet. @AndreyT the accepted answer in that question says to make a base ctor. I have one... oh. I guess i need to be calling the base class ctor, not the member ctor. ok.
    • AnT stands with Russia
      AnT stands with Russia over 10 years
      @WhozCraig: Even if it is a virtual base, it still won't let you initialize indirect members. Virtual inheritance might require initialization of indirect bases, but not members.
    • AnT stands with Russia
      AnT stands with Russia over 10 years
      @Steven Lu: The accepted answer says that a::m_z can only be initialized from a's constructor initializer list. It cannot be mentioned in b's constructor initializer list (as in your code). The language does not allow that. That's the point. I.e. you have to add another parameter to a's constructor specificallly for m_z (as you did for m_x) and pass the initial value from b through that constructor. BTW, in your code above you have to refer to a's constructor from b's constructor. Otherwise, it won't compile, since you have no default constructor in a.
    • Steven Lu
      Steven Lu over 10 years
      Got it, thanks. It's fine if this question is closed, but I think it should stay searchable so that clang users with this error can quickly track down the solution.
    • WhozCraig
      WhozCraig over 10 years
      @AndreyT So correct sir, I was momentarily distracted by a combination of sleep deprivation and the simultaneous arrival of a pizza. Eh. dropping comment.
  • Alexis Wilke
    Alexis Wilke over 3 years
    Your code example is wrong: OP meant to do m_z = z, not m_x = z and of course, the A(z) would be wrong in that case (and it also means m_z is not initialized in an A object and m_x not initialized in a B object).