Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   own initialization before calling parent's constructor (http://www.velocityreviews.com/forums/t806725-own-initialization-before-calling-parents-constructor.html)

avasilev 12-08-2011 01:07 PM

own initialization before calling parent's constructor
 
Hello,
The subject says it - is it legal to initialize fields of the derived
before calling the parent's consctructor, in the initialization list.
For example:

class Base
{
public:
int b;
B(int arg):b(arg){};
};

class Derived: public Base
{
int d;
int calculateValue() {return d+5};
Derived(int arg):
d(arg), B(calculateValue()){};
};

Greetings
Alex

Victor Bazarov 12-08-2011 02:03 PM

Re: own initialization before calling parent's constructor
 
On 12/8/2011 8:07 AM, avasilev wrote:
> The subject says it - is it legal to initialize fields of the derived
> before calling the parent's consctructor, in the initialization list.


What's the "parent"? A base class subobject?

> For example:
>
> class Base
> {
> public:
> int b;
> B(int arg):b(arg){};
> };
>
> class Derived: public Base
> {
> int d;
> int calculateValue() {return d+5};
> Derived(int arg):
> d(arg), B(calculateValue()){};


It's totally legal to write the code like that. It's not going to work
as you expect, though. First, the base class subobjects are initialized
in the order of their declaration, then the data members, *in the order
they are declared*. Of course, calling a member function with 'd'
uninitialized will have undefined behavior... But it's totally legal.

> };
>
> Greetings
> Alex


V
--
I do not respond to top-posted replies, please don't ask

Bart v Ingen Schenau 12-08-2011 03:09 PM

Re: own initialization before calling parent's constructor
 
avasilev Wrote:

> Hello,
> The subject says it - is it legal to initialize fields of the derived
> before calling the parent's consctructor, in the initialization list.


It is immaterial if it is legal or nor, because it is impossible.
The order of initialisation of a class's base-classes and members is not
dependent on the order they are specified in in the initializer-list, but
rather the order they are declared in in the class's definition.

If you compile your example with g++, with the warning flags -Wreorder or
-Wall, then g++ will complain that the initialization order is different
from the order in your initializer list.

> Greetings
> Alex


Bart v Ingen Schenau


avasilev 12-08-2011 04:10 PM

Re: own initialization before calling parent's constructor
 
On Dec 8, 5:09*pm, Bart v Ingen Schenau <b...@ingen.ddns.info> wrote:
> avasilev Wrote:
>
> > Hello,
> > The subject says it - is it legal to initialize fields of the derived
> > before calling the parent's consctructor, in the initialization list.

>
> It is immaterial if it is legal or nor, because it is impossible.
> The order of initialisation of a class's base-classes and members is not
> dependent on the order they are specified in in the initializer-list, but
> rather the order they are declared in in the class's definition.
>
> If you compile your example with g++, with the warning flags -Wreorder or
> -Wall, then g++ will complain that the initialization order is different
> 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.
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).

Alex

>
> > Greetings
> > Alex

>
> Bart v Ingen Schenau



avasilev 12-08-2011 04:12 PM

Re: own initialization before calling parent's constructor
 
On Dec 8, 4:03*pm, Victor Bazarov <v.baza...@comcast.invalid> wrote:
> On 12/8/2011 8:07 AM, avasilev wrote:
>
> > The subject says it - is it legal to initialize fields of the derived
> > before calling the parent's consctructor, in the initialization list.

>
> What's the "parent"? *A base class subobject?
>
> > For example:

>
> > class Base
> > {
> > public:
> > * * int b;
> > * * B(int arg):b(arg){};
> > };

>
> > class Derived: public Base
> > {
> > * *int d;
> > * *int calculateValue() {return d+5};
> > * *Derived(int arg):
> > * * *d(arg), B(calculateValue()){};

>
> It's totally legal to write the code like that. *It's not going to work
> as you expect, though. *First, the base class subobjects are initialized
> in the order of their declaration, then the data members, *in the order
> they are declared*. *Of course, calling a member function with 'd'
> uninitialized will have undefined behavior...


But I'm not doing this. My problem is that i need some derived-class
members initialized, in order to calculate the argument of the base's
constructor.

Alex

Victor Bazarov 12-08-2011 05:04 PM

Re: own initialization before calling parent's constructor
 
On 12/8/2011 11:12 AM, avasilev wrote:
> On Dec 8, 4:03 pm, Victor Bazarov<v.baza...@comcast.invalid> wrote:
>> On 12/8/2011 8:07 AM, avasilev wrote:
>>
>>> The subject says it - is it legal to initialize fields of the derived
>>> before calling the parent's consctructor, in the initialization list.

>>
>> What's the "parent"? A base class subobject?
>>
>>> For example:

>>
>>> class Base
>>> {
>>> public:
>>> int b;
>>> B(int arg):b(arg){};
>>> };

>>
>>> class Derived: public Base
>>> {
>>> int d;
>>> int calculateValue() {return d+5};
>>> Derived(int arg):
>>> d(arg), B(calculateValue()){};

>>
>> It's totally legal to write the code like that. It's not going to work
>> as you expect, though. First, the base class subobjects are initialized
>> in the order of their declaration, then the data members, *in the order
>> they are declared*. Of course, calling a member function with 'd'
>> uninitialized will have undefined behavior...

>
> But I'm not doing this. My problem is that i need some derived-class
> members initialized, in order to calculate the argument of the base's
> constructor.


Wrong. You don't need the data member initialized. If you think you
do, you're either don't understand the meaning of your base class and
its function, or your design is wrong. Generally speaking, what you
need is one place from which both the initialization of the base class
subobject will get its argument *and* the data member is going to be
initialized. For instance:

class Derived : public Base
{
static int calculateValue(int arg) { return arg+5; }
Derived(int arg) : Base(calculateValue(arg)), d(arg) {}
...

V
--
I do not respond to top-posted replies, please don't ask

Victor Bazarov 12-08-2011 05:05 PM

Re: own initialization before calling parent's constructor
 
On 12/8/2011 11:10 AM, avasilev wrote:
> On Dec 8, 5:09 pm, Bart v Ingen Schenau<b...@ingen.ddns.info> wrote:
>> avasilev Wrote:
>>
>>> Hello,
>>> The subject says it - is it legal to initialize fields of the derived
>>> before calling the parent's consctructor, in the initialization list.

>>
>> It is immaterial if it is legal or nor, because it is impossible.
>> The order of initialisation of a class's base-classes and members is not
>> dependent on the order they are specified in in the initializer-list, but
>> rather the order they are declared in in the class's definition.
>>
>> If you compile your example with g++, with the warning flags -Wreorder or
>> -Wall, then g++ will complain that the initialization order is different
>> 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.
> 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).


Either there *is* no such dependency (IOW, you are just *imagining* it)
or you introduced that dependency because your model is incorrect. Fix
your model or implement the dependency differently.

V
--
I do not respond to top-posted replies, please don't ask

Kevin McCarty 12-08-2011 05:27 PM

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 different
> > 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

avasilev 12-08-2011 06:22 PM

Re: own initialization before calling parent's constructor
 
> Either there *is* no such dependency (IOW, you are just *imagining* it)
> or you introduced that dependency because your model is incorrect. *Fix
> your model or implement the dependency differently.
>


The reason I am resorting to this, is actually because I would like to
do some caching of calculated result, which I then use to pass to the
base's constructor, and will use further in the object's lifetime for
other purposes. Normally I would store the result in a variable, and
not initialize any members, but given the limited syntax of
initializer lists, I cannot implement logic that I would do normal
code. Let me clarify with another example:

struct Base
{
Base(int v) {...};
}

struct Derived: public Base
{
int d;
void veryCostlyCalculation()
{
....
d = <calculation result>
}

Derived()
:veryCostlyCalculation(), Base(d) {}
};


In an initialization list, how can I store the result of
veryCostlyCalculation() in a local variable, so that I don't use
members?



avasilev 12-08-2011 06:40 PM

Re: own initialization before calling parent's constructor
 
Hi Kevin,
Thanks for the detailed response.
> 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


I think that says it all! That was also my doubt, and the reason to
ask.

> 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


This will not do - actually my purpose is to cache the result from the
calculation for later reuse, but in an initializer list I can't have
local variables, this is why I wanted to use a member variable for
this purpose.


> 2) Use two-phase initialization for the base object
> 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.


These will technically do the job, but my optimization is too small to
resort to complicating the design in such ways. I guess I will just
leave the optimization for later.
Thanks
Alex


All times are GMT. The time now is 01:23 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.