Discussion:
Initializing a base variable from a derived class
(too old to reply)
robbio
2010-10-21 18:39:47 UTC
Permalink
Hi All,

this is the scenario: I have two classes, a base one and a derived one:

class A
{
public:
A(...)
...
protected:
int m_nVariable;
};

class B : public A
{
public:

B(...)
: A()
, m_nVariable( 0 ) <<<< here is the problem
{
....
}
}

*At compile time*, the compiler says me that there is an "ilegal member
initialization: m_nVariable is not a base or a member".
But from the theory I know that m_nVariable visibility is public from B
so m_nVariable is a B's member too and I call it after the
initializzation of A().
If I put "m_nVariable = 0" inside the constructor of B (between { and })
all is fine.
So I don't understand why the compiler doesn't see, at compile time,
m_nVariable as member of B too, in the intialization list of B of course.
Is there a conceptual explanation for this?
I'm using VS2008 but I dont' think it's important.

Thank you,
Roberto
Bo Persson
2010-10-21 19:08:54 UTC
Permalink
Post by robbio
Hi All,
class A
{
A(...)
...
int m_nVariable;
};
class B : public A
{
B(...)
: A()
, m_nVariable( 0 ) <<<< here is the problem
{
....
}
}
*At compile time*, the compiler says me that there is an "ilegal
member initialization: m_nVariable is not a base or a member".
But from the theory I know that m_nVariable visibility is public
from B so m_nVariable is a B's member too and I call it after the
initializzation of A().
If I put "m_nVariable = 0" inside the constructor of B (between {
and }) all is fine.
So I don't understand why the compiler doesn't see, at compile time,
m_nVariable as member of B too, in the intialization list of B of
course. Is there a conceptual explanation for this?
I'm using VS2008 but I dont' think it's important.
The initializer list is used to initialize base classes and members,
not members of base classes. :-)

The members of A should be initialized by A, possibly using a
protected constructor.

class A
{
//...
protected:
A(int InitValue) : m_nVariable(InitValue)
{ }

private:
int m_nVariable;

};

class B : public A
{
public:
B() : A(0)
{ }

};


Bo Persson
robbio
2010-10-21 20:24:32 UTC
Permalink
Post by Bo Persson
Post by robbio
Hi All,
class A
{
A(...)
...
int m_nVariable;
};
class B : public A
{
B(...)
: A()
, m_nVariable( 0 )<<<< here is the problem
{
....
}
}
*At compile time*, the compiler says me that there is an "ilegal
member initialization: m_nVariable is not a base or a member".
But from the theory I know that m_nVariable visibility is public
from B so m_nVariable is a B's member too and I call it after the
initializzation of A().
If I put "m_nVariable = 0" inside the constructor of B (between {
and }) all is fine.
So I don't understand why the compiler doesn't see, at compile time,
m_nVariable as member of B too, in the intialization list of B of
course. Is there a conceptual explanation for this?
I'm using VS2008 but I dont' think it's important.
The initializer list is used to initialize base classes and members,
not members of base classes. :-)
The members of A should be initialized by A, possibly using a
protected constructor.
class A
{
//...
A(int InitValue) : m_nVariable(InitValue)
{ }
int m_nVariable;
};
class B : public A
{
B() : A(0)
{ }
};
Bo Persson
Sure. Maybe my scenario was not complete.
We know that B has a relation of "is-a" with A, so B is first of all an
A plus some new behaviour related to B.
For sure the A's member variable should be initialized from A first of
all and not from B. But since B is a specialized class of A
B could set the member variable with different values base on its
constructor and behaviour, after A's initialized phase of course.
Let's re-do my example:
....
/* constructor of B, a particular constructor different from the default */
B( int nNewValue )
: A(...)
, m_nVariable( nNewValue ) <<< in this way I want to change the value of
A's memeber variable (B's member variable too)
{
...
}
...


*At compile time* shouldn't be any problems of visibility or "is-a" os
"is-not-a" relations etc, because m_nVariable is a variable of B too.
At running time shouldn't be any problems too since A and all of its
members are intialized first ( : A(...) calling to the A constructor )
and only after the initialization process goes to initialize the other
variable in the list ( , m_nVariable( ... ) ).
Of course if I put m_nVariable( nNewValue ) in the body of the
constructor of B all is fine. So the problem is in the initialization
list...
I don't if it's clear what I mean...:)


Roberto
Ulrich Eckhardt
2010-10-22 07:14:24 UTC
Permalink
Post by robbio
We know that B has a relation of "is-a" with A, so B is first of all an
A plus some new behaviour related to B.
Okay.
Post by robbio
For sure the A's member variable should be initialized from A first of
all and not from B.
Even stronger, construction of A involves initialisation of each of its
member variables.
Post by robbio
But since B is a specialized class of A, B could set the member variable
with different values base on its constructor and behaviour, after A's
initialized phase of course.
Right, B can change the value, which is a normal assignment. Note that even
though it is during the constructor of B, it is not technically an
initialisation of said variable, but just an assignment. The variable was
already initialised as part of the baseclass ctor.
Post by robbio
....
/* constructor of B, a particular constructor different from the default
*/ B( int nNewValue )
: A(...)
, m_nVariable( nNewValue ) <<< in this way I want to change the value of
A's memeber variable (B's member variable too)
{
...
}
Not possible, use assignment.
Post by robbio
*At compile time* shouldn't be any problems of visibility or "is-a" os
"is-not-a" relations etc, because m_nVariable is a variable of B too.
At running time shouldn't be any problems too since A and all of its
members are intialized first ( : A(...) calling to the A constructor )
and only after the initialization process goes to initialize the other
variable in the list ( , m_nVariable( ... ) ).
Of course if I put m_nVariable( nNewValue ) in the body of the
constructor of B all is fine. So the problem is in the initialization
list...
Imagine this:

int x(5);
x(12);

This doesn't compile, the second line should have an assignment. Anyhow,
let's assume that the second line compiles and that it causes a second
initialisation of 'x'. In that case, consider this code:

std::string x("42");
x("3.143");

What kind of initialisation should the second line cause? Should it invoke
the constructor a second time? Should it first call the destructor? It
surely has to in order to release the resources allocated to 'x'. So, what
if the second invocation of the ctor fails, e.g. because it runs out of
memory? In that case, will the destructor be called again as part of the
destructor of your baseclass? Or maybe it should simply invoke the
assignment operator, but in that case it would be misplaced in an
initialiser list.


Summary: You have been given multiple alternatives, use those. Your approach
is to some extent reasonable, but it firstly is illegal in C++ and secondly
has a few problems as per the previous paragraph.

Uli
--
C++ FAQ: http://parashift.com/c++-faq-lite

Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
robbio
2010-10-22 07:43:09 UTC
Permalink
Post by Ulrich Eckhardt
Post by robbio
We know that B has a relation of "is-a" with A, so B is first of all an
A plus some new behaviour related to B.
Okay.
Post by robbio
For sure the A's member variable should be initialized from A first of
all and not from B.
Even stronger, construction of A involves initialisation of each of its
member variables.
Post by robbio
But since B is a specialized class of A, B could set the member variable
with different values base on its constructor and behaviour, after A's
initialized phase of course.
Right, B can change the value, which is a normal assignment. Note that even
though it is during the constructor of B, it is not technically an
initialisation of said variable, but just an assignment. The variable was
already initialised as part of the baseclass ctor.
Post by robbio
....
/* constructor of B, a particular constructor different from the default
*/ B( int nNewValue )
: A(...)
, m_nVariable( nNewValue )<<< in this way I want to change the value of
A's memeber variable (B's member variable too)
{
...
}
Not possible, use assignment.
Post by robbio
*At compile time* shouldn't be any problems of visibility or "is-a" os
"is-not-a" relations etc, because m_nVariable is a variable of B too.
At running time shouldn't be any problems too since A and all of its
members are intialized first ( : A(...) calling to the A constructor )
and only after the initialization process goes to initialize the other
variable in the list ( , m_nVariable( ... ) ).
Of course if I put m_nVariable( nNewValue ) in the body of the
constructor of B all is fine. So the problem is in the initialization
list...
int x(5);
x(12);
This doesn't compile, the second line should have an assignment. Anyhow,
let's assume that the second line compiles and that it causes a second
std::string x("42");
x("3.143");
What kind of initialisation should the second line cause? Should it invoke
the constructor a second time? Should it first call the destructor? It
surely has to in order to release the resources allocated to 'x'. So, what
if the second invocation of the ctor fails, e.g. because it runs out of
memory? In that case, will the destructor be called again as part of the
destructor of your baseclass? Or maybe it should simply invoke the
assignment operator, but in that case it would be misplaced in an
initialiser list.
Summary: You have been given multiple alternatives, use those. Your approach
is to some extent reasonable, but it firstly is illegal in C++ and secondly
has a few problems as per the previous paragraph.
Uli
I see it now! At the time of initialization of the member of A in B ctor
the variable member is already alive,
initialized by A ctor. I was in doubt because I used a simple base type
as member variable but if
m_nVariable was a complex object...Probably this is because the compiler
didn't allow it.

Thank you.
Roberto

Loading...