Understanding Base Class Initialization

Consider the program:

#include<iostream>
#include<vector>

struct A
{
    int a;
    A(int) { }
    virtual int foo(){ std::cout << "base" << std::endl; return 5; }
};

struct B : A
{
    int b;
    B(): b(9), A(foo()) { }
    virtual int foo(){ std::cout << "derived" << std::endl; return 6; }
};

B b; //prints derived

int main(){ }

      

DEMO

What Scott Meyers said in his Effective C++

about it:

At the time of constructing the base class of an object of a derived class, the type of object is the base class.

So, I expected what base

would be printed instead, because we were under constructing a base class by calling a function foo

. What am I missing? Could it be UB? If so, please point me to the appropriate section.

+3


source to share


3 answers


Scott means that although you are in the base class constructor, the normal rules for a virtual function do not work. So if you are in the constructor of the base class, then any virtual functions (of that base class) called inside the ctor will be called on the object that is currently being built in that very ctor.

This way your code prints the correct result: foo()

called in B

ctor not in parent constructor. If you called foo

inside the A

ctor, you would print base

.

The behavior is still undefined by the standard:



[12.6.2 / 13] Member functions (including virtual member functions, 10.3) can be called on an object under construction. Likewise, an object under construction can be the operand of a typeid operator (5.2.8) or dynamic_casting (5.2.7). However, if these operations are performed in the ctor initializer (or in a function called directly or indirectly from the ctor initializer) before all mem initializers for base classes have completed, the result of the operation is undefined.

But you should understand that "undefined" here means that you can use some internal state in the called function. Since you don't know, the behavior will be consistent, but the standard still considers it undefined. The "undefined" part has nothing to do with what is printed, but rather what can be accessed in the member function.

+3


source


Just don't use virtual functions in constructors - item 9



+1


source


What Scott Myers says, but your program is wrong.

 B(): b(9), A(foo()) { } 

      

This statement is completely wrong:

In the initialization list of the derived class constructor, you must first call the base class constructor before you initialize the class member object. You cannot use a non-stationary member function before creating an object.

#include<iostream>
#include<vector>

struct A
{
    int a;
    A(int) { std::cout<<"base constructed\n"; }
    virtual int foo(){ std::cout << "base" << std::endl; return 5; }
};

struct B : A
{
    int b;
    B():  A(6), b(9) { std::cout<<"derived constructed"; }
    virtual int foo(){ std::cout << "derived" << std::endl; return 6; }
};



int main(){
    B b; //prints derived
    }

O/P

base constructed

derived constructed

      

0


source







All Articles