24
class A {
        int i;
public: 
        A() {cout<<"in A's def const\n";};
        A(int k) {cout<<"In A const\n";  i = k; }
        };

class B : virtual public A {
public:
        B(){cout<<"in B's def const\n";};
        B(int i) : A(i) {cout<<"in B const\n";}
        };

class C :   public B {
public:
        C() {cout<<"in C def cstr\n";}
        C(int i) : B(i) {cout<<"in C const\n";}
        };

int main()
{
        C c(2);
        return 0;
}

The output in this case is

in A's def const
in B const
in C const

Why is this not entering into in A const

`It should follow the order of 1 arg constructor call. But what actually is happening on deriving B from A using virtual keyword.

There are few more question

Even if I remove the virtual keyword in above program and remove all the default constructor it gives error. So, why it needs the def constructor

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Kunal
  • 511
  • 2
  • 6
  • 12

3 Answers3

19

The constructors for virtual base classes are always called from the most derived class, using any arguments it might pass in. In your case, the most derived class doesn't specify an initializer for A, so the default constructor is used.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 1
    @james....you mean to say that the most derived class here i.e C should specify the initializer for A. But, on removing A default constructor and adding C(int i) : A(i),B(i) in C's constructor it doesnt work – Kunal May 10 '12 at 12:50
  • @MikeDeSimone...ya i have written the same but removed A's default constructor but i get compilation error...can you please explain why this is so..and how to take care if i have a complex inheritance involved in. – Kunal May 10 '12 at 12:51
  • @Kunal: Yeah, I deleted my comment because you actually tried it. So here we have an answer, up voted, that fails to work. @James, please explain how to fix the code so the `A(int)` constructor is called. – Mike DeSimone May 10 '12 at 12:52
  • You don't need to remove A's default ctor, just add the initialisation to C as in `C(int i) : A(i), B(i)` then compiles fine. – acraig5075 May 10 '12 at 12:56
  • @acraig5075...ya I have done the same but instead i have removed A's default constructor...wondering why def A constructor is required here ? – Kunal May 10 '12 at 12:59
  • @Kunal: You could remove A's default ctor if you give a default parameter to the other ctor `A(int k=0)` – acraig5075 May 10 '12 at 13:13
  • 2
    What is that error after removing A's default constructor? Isn't is a problem with B's and C's default constructors which now have to be extended by an explicit call to A constructor? – Adam Badura May 10 '12 at 13:22
  • 1
    As long as `B` (or `C`) has a constructor which doesn't specify an initializer for `A`, `A` must have a default constructor. The fact that you never actually call the constructor doesn't mean that the compiler doesn't generate the code for it, and the generated code will try to call `A()` (conditionally, with a test as to whether it is the most derived class). – James Kanze May 10 '12 at 14:25
  • 2
    @MikeDeSimone The `A(int)` constructor will be called if the most derived class specifies it in the initialization list: e.g. `C::C(int i) : A(i), B(i) {}` The initialization of virtual bases is always done by the most derived class. – James Kanze May 10 '12 at 14:27
8

As JamesKanze has explained, in case of virtual inheritance it is the most derived class that calls the virtual base class' constructor. So, if you want A's constructor that takes an integer to be called, you need to add that to C's initialization list.

C(int i) : A(i), B(i) {cout<<"in C const\n";}

For the second part of your question, default constructors are not required, but then the derived class must call the non-default constructor explicitly, since the compiler is unable to do that for you in the absence of a non-default constructor.

#include <iostream>
using namespace std;

class A {
  int i;
public:
  // A() {cout<<"in A's def const\n";};
  A(int k) {cout<<"In A const\n";  i = k; }
};

class B : virtual public A {
public:
  // B(){cout<<"in B's def const\n";};
  B(int i) : A(i) {cout<<"in B const\n";}
};

class C :   public B {
public:
  C() : A(42), B(42) {cout<<"in C def cstr\n";}
  C(int i) : A(i), B(i) {cout<<"in C const\n";}
};

int main()
{
  C c(2), c2;
  return 0;
}

This prints out

In A const
in B const
in C const
In A const
in B const
in C def cstr
Community
  • 1
  • 1
Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • @praetorian...thanks for your answer. But still I am unclear with one thing....why is it necessary to give C() : A(42), B(42) there ?? Please clarify – Kunal May 10 '12 at 13:27
  • 2
    @Kunal Every derived class constructor (for non-POD types) must initialize its base class constructor. When you don't explicitly list the base constructor, the compiler will call the default constructor for you. If no such default base constructor exists, you must explicitly call an existing base constructor. – Praetorian May 10 '12 at 13:37
  • 1
    does that mean A() will be called twice? what happens with the call to A() inside B()? – Youda008 Apr 09 '16 at 14:19
  • 1
    @Youda008 No, `A()` is not called twice. In the example output statements, the first 3 lines are printed during the construction of `c` and the next 3 are printed during construction of `c2`. The call to `A`'s constructor made within `B`'s mem-initializer list will only be executed if you construct a `B`. If you construct a `C`, then that class is responsible for constructing `A`. – Praetorian Apr 11 '16 at 04:41
2

There are two questions here.

Why is this not entering into in A const?

Because you are using virtual inheritance.

When you use virtual inheritance, the Initialization list of most-derived-class's ctor directly invokes the virtual base class's ctor.. In this case, that means that C's constructor calls A's constructor directly. Since you have not specified which A constructor to call in C's initialization list, the default constructor is called.

This is fixed by changing your implementation of C::C(int) to:

C(int i) : A(i), B(i) {cout<<"in C const\n";}

If I remove the virtual keyword in above program and remove all the default constructor it gives error. So, why it needs the def constructor?

Because B also doesn't specify which A ctor to call, so the default constructor is used. If you remove As def ctor, B can't be compiled.

John Dibling
  • 99,718
  • 31
  • 186
  • 324