1

I read that in virtual inheritance, constructors are called "from the most derived". consider the following code. In my opinion, the most derived class here is D. then B and C and the "most-not-derived" is A. So how come the most "Base" constructor is called first and not the "most derived"? Thanks.

#include <iostream>
using namespace std;

struct A
{
    A()
    {
        cout << "A default constructor" << endl;
    }
};

struct B : virtual public A
{
    B() : A()
    {
        cout << "B default constructor" << endl;
    }
};

struct C : virtual public A
{
    C() : A()
    {
        cout << "C default constructor" << endl;
    }
};

struct D : public B, public C
{
    D() : B(), C()
    {
        cout << "D default constructor" << endl;
    }
};

int main()
{
    D d;
}

This is the output :

A default constructor
B default constructor
C default constructor
D default constructor

UPDATE:


Ok. so consider the following code. Notice that 10 was printed although D,B and C constructors sent 7. Here actually the base class IS the first one that is called. There was no chain from D to B to A. A() was called first (actually it's default constructor). and only then B and C constructors were called.

But I read : "from the most derived." Source : c++ virtual inheritance

the most derived here is D then B and C and only then A. So how come that A is called first without even considering the parameters B,D,C transfer to it from their constructors ? Thanks.

The code :

#include <iostream>
using namespace std;

struct A
{
    int _x;
    A()
    {
        _x = 10;
        cout << "A default constructor" << endl;
    }
    A(int x)
    {
        _x = x;
        cout << "A NOT-default constructor" << endl;
    }
};

struct B : virtual public A
{
    B(int x=7) : A(x)
    {
        cout << "B  constructor" << endl;
    }
};

struct C : virtual public A
{
    C(int x=7) : A(x)
    {
        cout << "C  constructor" << endl;
    }
};

struct D : public B, public C
{
    D(int x=7) : B(x), C(x)
    {
        cout << "D  constructor" << endl;
    }
};

int main()
{
    D d;
    cout << d._x;
}

The output :

A default constructor
B  constructor
C  constructor
D  constructor
10
Community
  • 1
  • 1
user2630165
  • 311
  • 3
  • 10
  • 4
    Where did you read that? If constructors were called in the order of most to least derived, none of the constructors would be able to reference anything in the base class(es), since the base part of the instance wouldn't have been constructed yet! The output you're receiving is correct. – Cameron Sep 15 '14 at 16:05
  • 1
    THe most derived constructor first initializes the virtual base-classes in source-file order. Where's the difficulty? – Deduplicator Sep 15 '14 at 16:06
  • 3
    The problem is that you're outputting at the end of the constructor. The derived constructor is being called first, but it calls the parent constructor **and then** your output. – leemes Sep 15 '14 at 16:18
  • 2
    To directly answer your question: the most-derived constructor *is* being called first, but before it executes the first line of code it also calls the base class constructors. That's why it doesn't print `"D constructor"` first. – Mark Ransom Sep 15 '14 at 21:58

5 Answers5

6

Construction order is quite simple in C++:

  1. You call a most-derived ctor (By initializing a variable; auto-storage-class, static, dynamic, whatever).
  2. That ctor initializes all sub-objects:
    • A delegating ctor calls another most-derived-ctor.
    • A non-delegating ctor does the work itself:
      1. Iff the most-derived ctor, virtual bases in left-first declaration-order. (That means arguments to the virtual-base ctor given by non-most-derived-ctors are ignored)
      2. The other direct bases in left-first declaration-order.
      3. The members in declaration-order.
  3. The ctors body runs.

As your most-base ctor is for the only virtual base, its body is the first ctor-body to run, called directly by the most-derived ctor.

In general, calling virtual functions, typeid and dynamic_cast is safe, though not before the base-subobjects are all initialized: May I call a virtual function to initialize a base-class sub-object?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
4

That means that it's the responsibility of the most derived class to initialise any virtual base sub-objects, as well as those that it immediately derives from. That is, all the base constructors are called from the most-derived constructor: the constructor for D calls the constructor for A, then B and C, and finally initialises itself. This is necessary to ensure that the shared base object is initialised just once, and before any of the classes that derive from it.

It doesn't mean that the order is from the most to least derived. As with regular inheritance, base sub-objects are always initialised first, so they're available when initialising the derived classes.

To answer your updated question, since D initialises A, it will call the default constructor unless its initialiser list contains an entry for A:

D(int x=7) : B(x), C(x)        // calls A(), initialising with 10
D(int x=7) : A(x), B(x), C(x)  // calls A(int), initialising with 7

Any entry for A in the initialiser list of B (or C) is only used when B (or C) is the most derived class (and so is responsibly for initialising A).

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
1

How do you propose any derived class to behave if its constructor code ran before the base class was constructed? While technically possible, it'd be entirely useless.

The behavior you observe is the only sane one, and has nothing to do with virtual inheritance.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
1

You said

I read that in virtual inheritance, constructors are called "from the most derived".

That is true. Let me elaborate.

In your case, D is the most derived.

When you construct an instance of D, the constructors for A is called from the constructor of D since there is only instance of A for each instance of D. Constructor for A will not be called from the constructor of B or C.

When you construct an instance of B, then constructor for A is called from the constructor of B. Similarly for an instance of C.

If you had a sub-type of D,

struct E : public D
{
};

and you create an instance of E, then the constructor of A will be called from the constructor of E.

The C++ Draft Standard (N3337) says this about initialization involving virtual base classes:

12.6.2 Initializing bases and members

5 Initialization shall proceed in the following order:

— First, and only for the constructor of the most derived class as described below, virtual base classes shall be 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 class names in the derived class base-specifier-list.

Community
  • 1
  • 1
R Sahu
  • 204,454
  • 14
  • 159
  • 270
0

That is how objects are built.

UPDATE

Check this example out:

class A{
    A()
    {
    cout << "Constructor A"<<endl;
    }

    ~A()
    {
    cout << "Destructor A"<<endl;
    }
}

class B : public A{
    B()
    {
    cout << "Constructor B"<<endl;
    }

    ~B()
    {
    cout << "Destructor B"<<endl;
    }
}
class C : public B{
    C()
    {
    cout << "Constructor C"<<endl;
    }

    ~C()
    {
    cout << "Destructor C"<<endl;
    }
}

Creating an object of class C:

C obj;

The output will be as follows:

Constructor A
Constructor B
Constructor C
Destructor C
Destructor B
Destructor A

The reason for the execution is this:

When a class derives from another class, it derives the properties of that class. Functionalities of the derived class may or may not depend on the functionalities of the base class, but it can never be the other way. Assuming the derived class depends on the base class functionalities, it is important that the base class is properly initialized before the derived class can be initialized.

UPDATE:

When an object of C is made, he control from C constructor is transferred to it's base class' constructor, before C's constructor can execute. That's what I meant by base class first.

UPDATE:

Your question can be best answered by drawing the object relationship.
We'll have A right on the top and D at the bottom.

"in virtual inheritance, [virtual base] constructors are called from the most derived" [type's constructor]. "

By the above statement, they're asking you to start from the most derived type's constructor (D) and transverse up to the most base class' (A) constructor.

UPDATE:

@leemes has made the execution flow clearer in the comments:

It is the constructor itself which "redirects" to the base's constructor. After this returns, it continues with its own constructor. What you miss is that what is written in curly braces is not the whole implementation. It's only what comes after the call to the base ctor and initializing the member variables. Same with ctor: You write in curly braces what is to be executed before calling the ctor of member variables and then the ctor of the base.

galdin
  • 12,411
  • 7
  • 56
  • 71
  • "in virtual inheritance, [virtual base] constructors are called from the most derived" [type's constructor]. " There's obvious confusion here you're not addressing – Mooing Duck Sep 15 '14 at 16:11
  • "Constructors are executed from base to derived, and destructors are executed from derived to base." No. It's the other way around. – leemes Sep 15 '14 at 16:19
  • Apparently you're misunderstanding me, so I'll try by example this time: http://coliru.stacked-crooked.com/a/74ab1c082de9d984 Virtual-base-constructors are called from the mem-initializer-list for the most-derived-type's-constructor. – Mooing Duck Sep 15 '14 at 16:24
  • @gldraphael Still not correct. It is the constructor itself which "redirects" to the base's constructor. After this returns, it *continues* with its own constructor. What you miss is that what is written in curly braces is not the whole implementation. It's only what comes *after* the call to the base ctor and initializing the member variables. Same with ctor: You write in curly braces what is to be executed *before* calling the ctor of member variables and then the ctor of the base. – leemes Sep 15 '14 at 16:36