Topic: Why must "most derived class" initialize all virtual base classes?
Author: hanlon@birch307.cray.com (Jim Hanlon)
Date: 1995/04/05 Raw View
Although I could find no illumination to my question in the FAQ, I hope this
question isn't a regular.
I ran headlong into the behavior dictated by the paragraph on page 293 of
ARM section 12.6.2 and am looking for clues into *why* virtual base class
initialization is specified as it is?
The paragraph of interest (section 12.6.2, p293) follows a discussion of
constructor call ordering in the presense of virtual base classes. It reads:
"A complete object is an object that is not a sub-object representing a base
class. Its class is said to be the most derived class for the object. All
sub-objects for virtual base classes are initialized by the constructor of the
most derived class. If a constructor of the most derived class does not specify
a mem-initializer for a virtual base class then that virtual base class must have
a default constructor or no constructors. Any mem-initializers for virtual
classes specified in a constructor for a class that is not the class of the
complete object are ignored. For example,"
(An example follows which does little or nothing, IMHO, to shed light on what the
paragraph says.)
Here is an example testcase that I was having problems with:
class A {
public:
A(int = 0);
int x;
};
class B {
public:
B(A&);
A& aref;
};
class C : public virtual B {
public:
C(A&);
};
class D : public virtual B {
public:
D(A&);
};
class E : public virtual C, public virtual D {
public:
E(A&);
};
A::A(int i) : x(i) { ; }
B::B(A& a) : aref(a) { ; }
C::C(A& a) : B(a) { ; }
D::D(A& a) : B(a) { ; }
E::E(A& a) : C(a), D(a) { ; }
int main(int, char **)
{
A a(4);
B b(a);
C c(a);
D d(a);
E e(a);
}
Compiling under Sun C++ 4.0.1 (Solaris 2.3 on sparc) you get:
% CC -V -o testcase testcase.cc
CC: SC3.0.1 02 Mar 1995
ccfe: SC3.0.1 03 Mar 1995 C++4.0.1 patch 101910-07
"testcase.cc", line 36: Error: E::E(A&) can't find B::B() to initialize base class.
Compiling with g++ 2.6.3 (??? I'm guessing. I rarely use g++/gcc :-) you get
% g++ -o testcase testcase.cc
testcase.cc: In method `E::E(A &)':
testcase.cc:36: virtual baseclass `B' does not have default initializer
Changing the initializer list on E's constructor to explicitly initialize B
(per ARM section 12.6.2) causes all things to be well:
% diff testcase.cc testcase.cc~
36c36
< E::E(A& a) : B(a), C(a), D(a) { ; }
---
> E::E(A& a) : C(a), D(a) { ; }
% CC -V -o testcase testcase.cc
CC: SC3.0.1 02 Mar 1995
ccfe: SC3.0.1 03 Mar 1995 C++4.0.1 patch 101910-07
tdb_link: SC3.0.1 03 Mar 1995 C++4.0.1 patch 101910-07
% testcase
% g++ -o testcase testcase.cc
% testcase
My question is "Why?" This specification seems to blow all hope of encapsulation
out of the water, since E must know all the details of it's derivation graph.
I can't see the need or benefit in this form of initialization.
What is the reason for this? Why are mem-initializers for virtual classes
specified in constructors for classes that are not the class of the complete
object (most derived class, i.e. 'e' above) ignored?
I would prefer to hear your thoughts by email.
Thanks!
Jim Hanlon (internet) hanlon@cray.com
Cray Research, Inc. (telephone) 612-683-5443
655F Lone Oak Drive, Eagan, MN 55121 (fax) 612-683-5599
--
Jim Hanlon (internet) hanlon@cray.com
OWS Development (UUCP) uunet!cray!hanlon
Cray Research, Inc. (telephone) 612-683-5443