Derived class doesn't call base class default ctor

Hi guys. Here is the code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include "stdafx.h"
#include <iostream>

using namespace std;

class A
{
public:
	A(){
		cout << "default constr A" << endl;
	}
	A(int i){
		cout << "constr A called from"  << i << endl;
	}
	void foo(){ cout << "function call" << endl; }
};

class B : public virtual A {
public:
	B():A(1){
		cout << "default constr B" << endl;
	}
};

class C : public virtual  A {
public:
	C():A(2){
		cout << "default constr C" << endl;
	}
};

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


int _tmain(int argc, _TCHAR* argv[])
{
	D d;
	d.foo();

	return 0;
}



I start to play with virtual inheritance which is works great here the output is :
default constr A
default constr B
default constr C
default constr D
function call

Then I was curious how the program handle the situation when the default constructor of the classes B and C, call the specific base ctor
1
2
B():A(1)
C():A(2)


and I was very surprised when the program kind of ignore the specific base ctor I called.

So my question is why ? THANKS IN ADVANCE

So my question is why ?
Which constructor do you think it should call, A(1) or A(2)? The choice would be somewhat arbitrary.

I looked this up in my C++11 Working Draft and found in section 12.6.2:
A mem-initializer where the mem-initializer-id denotes a virtual base class is ignored during execution of a constructor of any class that is not the most derived class.

The Working Draft is out of date but I suspect this part hasn't changed. I think the quote makes sense. Since A is virtual, your D object has only one of them, and if you want to initialize it with something other than the default constructor, you need to specfy that in D's initialization list. So if you change line 34 to:
D() : A(1)
Then the output is:
constr A called from1
default constr B
default constr C
default constr D
function call

B():A(1) C():A(2)
you're trying to member initialize the default ctors of the derived classes (i.e which takes no arguments) through member intiailization with an overload of the base class ctor that takes an int argument. So the int argument is redundant as far as the derived class ctor's are concerned. You could pass on the base class ctor overload to the dervied class ctor's directly, in the following manner:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>

using namespace std;

class A
{
public:
	A(){
		cout << "default constr A" << endl;
	}
	A(int i){
		cout << "constr A called from "  << i << endl;
	}
	void foo(){ cout << "function call" << endl; }
};

class B : public virtual A {
public:
  	B(){
		A(1);
		cout << "default constr B" << endl;
	}
};

class C : public virtual  A {
public:
	C(){
		A(2);
		cout << "default constr C" << endl;
	}
};

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

};


int main()
{
	D d;
    d.foo();



	return 0;
}
Gunnerfunner, I don't think that's right. Lines 20 and 28 in your example simply create a temporary A object, they don't initialize the base class object. You can see that by adding a destructor to A and printing the address of the A object in the debug output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>

using namespace std;

class A
{
  public:
    A()
    {
	cout << "default constr A at " << this << endl;
    }
    A (int i)
    {
	cout << "constr A called from " << i << " at " << this << endl;
    }
    ~A() {
	cout << "destroying A at " << this << '\n';
    }
    void foo()
    {
	cout << "function call" << endl;
    }
};

class B:public virtual A
{
  public:
    B()
    {
	A(1);
	cout << "default constr B" << endl;
    }
};

class C:public virtual A
{
  public:
    C()
    {
	A(2);
	cout << "default constr C" << endl;
    }
};

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

};

int
main()
{
    D d;
    d.foo();

    return 0;
}

default constr A at 0xffffcbf0        <<--- D::A constructed
constr A called from 1 at 0xffffcb7f  <<--- A object at line 20 constructed
destroying A at 0xffffcb7f            <<--- A object at line 20 destroyed
default constr B
constr A called from 2 at 0xffffcb7f  <<--- A object at line 28 constructed
destroying A at 0xffffcb7f            <<--- A object at line 28 destroyed
default constr C
default constr D
function call
destroying A at 0xffffcbf0            << D::A destroyed

OP
was curious how the program handle the situation when the default constructor of the classes B and C, call the specific base ctor
s/he didn't mention anything about
initialize the base class object
or rather, i think you might be implying, using the base class object created through the call to the base class ctor to initialize the derived instance. of course, that'd be handled quite differently
closed account (48T7M4Gy)
http://stackoverflow.com/questions/21558/in-c-what-is-a-virtual-base-class
Topic archived. No new replies allowed.