54

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
  • 41,389
  • 58
  • 210
  • 364
  • 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. – Steven Lu Aug 28 '13 at 04:12
  • @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 Aug 28 '13 at 04:13
  • 4
    @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`. – AnT stands with Russia Aug 28 '13 at 04:15
  • 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. – Steven Lu Aug 28 '13 at 04:16
  • @AndreyT So correct sir, I was momentarily distracted by a combination of sleep deprivation and the simultaneous arrival of a pizza. Eh. dropping comment. – WhozCraig Aug 28 '13 at 04:21

1 Answers1

69

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;
}
Community
  • 1
  • 1
4pie0
  • 29,204
  • 9
  • 82
  • 118
  • 3
    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). – Alexis Wilke Jan 09 '21 at 20:55