[prog] C++ inheritance - destructors

Jimen Ching jching at flex.com
Wed May 28 19:02:53 EST 2003


On Wed, 28 May 2003, Sue Stones wrote:
>> I should add that the virtual base class must be initialized by the most
>> derived class.  In other words, you can't expect intermediate base classes
>> to initialize its own base class.  This is a non-obvious behavior that I
>> discovered when I started C++ programming.
>I'm sorry I don't understand what you're talking about, could you explain
>this please.

Take this example:

-------------------------------------------------------
#include <iostream>

using namespace std;

class V {
public:
        V();
        V(int);
};

class A : public virtual V {
public:
        A();
        A(int);
};

class B : public virtual V {
public:
        B();
        B(int);
};

class C : public A, public B {
public:
        C();
        C(int);
};

class D : public A, public B {
public:
        D();
        D(int);
};

class E : public A, public B {
public:
        E();
        E(int);
};

V::V() { cout << "V::V" << endl; }
A::A() { cout << "A::A" << endl; }
B::B() { cout << "B::B" << endl; }
C::C() { cout << "C::C" << endl; }
D::D() { cout << "D::D" << endl; }
E::E() { cout << "E::E" << endl; }
V::V(int i) { cout << "V::V " << i << endl; }
A::A(int i) : V(i) { cout << "A::A " << i << endl; }
B::B(int i) { cout << "B::B " << i << endl; }
C::C(int i) { cout << "C::C " << i << endl; }
D::D(int i) : A(i) { cout << "D::D " << i << endl; }
E::E(int i) : V(i), A(i) { cout << "E::E " << i << endl; }

V v(1); // use V(int)
A a(2); // use V(int)
B b(3); // use V()
C c(4); // use V()
D d(5); // use V(), not V(int) via A(int)
E e(6); // use V(int), via direct mem-initializer

int main()
	{
	return 0;
	}
---------------------------------------------------

This code will produce the following result with g++:

V::V 1
V::V 2
A::A 2
V::V
B::B 3
V::V
A::A
B::B
C::C 4
V::V
A::A 5
B::B
D::D 5
V::V 6
A::A 6
B::B
E::E 6

Notice that D(int) will call A(int), but A(int) will not call V(int).  And
in not doing so, the compiler ignored the source code for A(int).

Notice also that E(int) calls V(int) and A(int), but A(int) still doesn't
call V(int).  V is only constructed once directly by E(int).

This is what's meant by the most derived class must call the virtual
base's (non-default) constructor.  As we see in the construction of 'e',
this behavior is required to correctly construct a virtual V.

Hope this helps.

--jc

P.S.  The ISO C++ spec has a similar example.  But it didn't point out
this behavior explicitly.  The example had a private virtual V in class C.
For me, this made it ambiguous whether V(int) was needed in the most
derived class for this private copy, or because of the public virtual copy
from A and B.  If you understood what this rule meant, then the example
makes sense.  But if you didn't understand to begin with, the example is
confusing.

-- 
Jimen Ching (WH6BRR)      jching at flex.com     wh6brr at uhm.ampr.org


More information about the Programming mailing list