Re: own initialization before calling parent's constructor
On Dec 8, 8:10 am, avasilev <alxvasi...@gmail.com> wrote:
On Dec 8, 5:09 pm, Bart v Ingen Schenau <b...@ingen.ddns.info> wrote:
If you compile your example with g++, with the warning flags -Wreorder =
or
-Wall, then g++ will complain that the initialization order is differen=
t
from the order in your initializer list.
Yes, you are right about the warning. AFAIK, it is there to prevent
initializing mutually-dependent members which are not initialized in
the sequence specified in the class declaration.
Realize that the base class (or classes) is also in some respects a
member of the derived class, and is always initialized (including, per
12.6.2 of C++ 2003 standard, the evaluation of any of its constructor
arguments) before any other members of the derived class.
In my case, however, I don't have such a dependency. In fact, I have a
reverse dependency - the call to the base constructor depends on some
derived-class members being initialized already. Of course the abse
constructor itself will never depend on derived class members, but
here I'm talking about constructor arguments (see example).
Then your code is simply not going to work. That's just how the
language is. The derived class instance (and any non-static members
of it) does not yet exist at the time the base class constructor is
invoked and an attempt is made to evaluate Derived::calculateValue().
It will quite possibly return garbage. If you are very unlucky, it
will work by accident until you upgrade to a new compiler version or
change platforms or something.
You have a few alternatives for a work around, all of which have their
ups and downs:
1) Use a static member function of the derived class for the
calculation
class Base
{
public:
int b;
// your constructor was misnamed "B"
Base(int arg):b(arg){}
};
class Derived: public Base
{
int d;
// added static function
static int calculateValueFrom(int arg) { return arg+5; }
// you probably want ctor and calc fn to be public
public:
// rewrite non-static in terms of static to avoid redundancy
int calculateValue() { return calculateValueFrom(d); }
Derived(int arg):
Base(calculateValueFrom(arg)), d(arg) { }
};
2) Use two-phase initialization for the base object
class Base
{
public:
int b;
// added default ctor
Base() : b(0) { }
Base(int arg):b(arg){}
protected:
// added setter for b
void setB(int arg) { b = arg; }
};
class Derived: public Base
{
int d;
// again, added public keyword here
public:
int calculateValue() {return d+5;}
Derived(int arg):
Base(), // not actually needed, used by default
d(arg)
{ setB(calculateValue()); } // 2-phase init
};
3) Multiple inheritance: move the calculation logic into another base
class, and rely on the fact that base class constructors are called in
the order in which they are inherited from.
// Calculation logic moved here
class Calculator
{
protected: // presuming Derived needs access
int d;
public:
int calculateValue() {return d+5;}
Calculator(int arg) : d(arg) { }
};
class Base
{
public:
int b;
Base(int arg):b(arg){}
};
class Derived:
public Calculator, public Base // must have this order
{
public:
Derived(int arg):
Calculator(arg),
// C++03 std 12.6.2 ensures that Calculator is
// constructed when calculateValue() is called:
Base(calculateValue()) { }
};
- Kevin B. McCarty