member initializer does not name a non-static data member or base class
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;
}
Related videos on Youtube
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, 2020Comments
-
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 over 10 yearsWhy? 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 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 over 10 years@Steven Lu: The accepted answer says that
a::m_z
can only be initialized froma
's constructor initializer list. It cannot be mentioned inb
'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 toa
's constructor specificallly form_z
(as you did form_x
) and pass the initial value fromb
through that constructor. BTW, in your code above you have to refer toa
's constructor fromb
's constructor. Otherwise, it won't compile, since you have no default constructor ina
. -
Steven Lu over 10 yearsGot 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 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 over 3 yearsYour code example is wrong: OP meant to do
m_z = z
, notm_x = z
and of course, theA(z)
would be wrong in that case (and it also meansm_z
is not initialized in an A object andm_x
not initialized in a B object).