Topic: 257. Abstract base constructors and virtual base initialization
Author: lester@hep.phy.cam.ac.uk (Christopher Lester)
Date: Wed, 24 Mar 2004 09:17:04 +0000 (UTC) Raw View
Today I came across active issue number 257 in the C++ Standard Core
Language Active Issues list, issue 29. See for example:
http://std.dkuug.dk/jtc1/sc22/wg21/docs/cwg_active.html#257
.. whose relevant part I copy at the foot of this mail.
If any of you reading this posting happen to be members of the above
working group, I would like to encourage you to review the suggestion
contained therein, as it seems to me that the final tenor of the
submission is both (a) correct (the silence of the standard DOES
mandate the omission) and (b) describes what most users would
intuitively expect and desire from the C++ language as well.
The suggestion is to make it clearer that constructors for abstract
base classes should not be required to provide initialisers for any
virtual base classes they contain (as only the most-derived class has
the job of initialising virtual base classes, and an abstract base
class cannot possibly be a most-derived class).
For example:
struct A {
A(const int i, const int j) {};
};
struct B1 : virtual public A {
virtual void moo()=0;
B1() {}; // (1) Look! not "B1() : A(5,6) {};"
};
struct B2 : virtual public A {
virtual void cow()=0;
B2() {}; // (2) Look! not "B2() : A(7,8) {};"
};
struct C : public B1, public B2 {
C() : A(2,3) {};
void moo() {};
void cow() {};
};
int main() {
C c;
return 0;
};
I believe that, by not expressly forbidding it, the standard does
(and should!) allow the above code. However, as the standard doesn't
expressly allow it either (have I missed something?) there appears to
be room for misunderstanding. For example, g++ version 3.2.3 (and
maybe other versions as well) rejects the above code with messages
like:
In constructor `B1::B1()':
no matching function for call to `A::A()'
candidates are: A::A(const A&)
A::A(int, int)
Fair enough, the standard is perhaps not clear enough. But it seems
to be a shame that although this issue was first raised in 2000, we
are still living with it today.
Note that we can work-around, and persuade g++ to compile the above
by either (a) providing a default constructor A() for A, or (b)
supplying default values for i and j in A(i,j), or (c) replace the
construtors B1() and B2() with the forms shown in the two comments in
the above example.
All three of these workarounds may at times be appropriate, but
equally there are other times when all of these workarounds are
particularly bad. (a) and (b) may be very bad if you are trying to
enforce string contracts among objects, while (c) is just barmy (I
mean why did I have to invent random numbers like 5, 6, 7 and 8 just
to get the code to compile?).
So to to round up, then, my plea to the working group is:
"at the very least, please make the standard clearer on
this issue, but preferrably make the decision to expressly allow
code that looks something like the above"
Yours truly,
Christopher Lester
Dept of Physics, University of Cambridge, CB3 0HE, U.K.
---- Copy of active issue 257: --------------
257. Abstract base constructors and virtual base initialization
Section: 12.6.2 class.base.init Status: open Submitter: Mike
Miller Date: 1 Nov 2000
Must a constructor for an abstract base class provide a
mem-initializer for each virtual base class from which it is directly
or indirectly derived? Since the initialization of virtual base
classes is performed by the most-derived class, and since an abstract
base class can never be the most-derived class, there would seem to
be no reason to require constructors for abstract base classes to
initialize virtual base classes.
It is not clear from the Standard whether there actually is such a
requirement or not. The relevant text is found in 12.6.2
class.base.init paragraph 6:
All sub-objects representing virtual base classes are initialized by
the constructor of the most derived class (1.8 intro.object). If the
constructor of the most derived class does not specify a
mem-initializer for a virtual base class V, then V's default
constructor is called to initialize the virtual base class subobject.
If V does not have an accessible default constructor, the
initialization is ill-formed. A mem-initializer naming a virtual base
class shall be ignored during execution of the constructor of any
class that is not the most derived class.
This paragraph requires only that the most-derived class's
constructor have a mem-initializer for virtual base classes. Should
the silence be construed as permission for constructors of classes
that are not the most-derived to omit such mem-initializers?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]