C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Virtual inheritance and constructors in base classes with co

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language (comp.lang.c++)
View previous topic :: View next topic  
Author Message
Xavier
Guest





PostPosted: Fri Apr 29, 2005 9:54 am    Post subject: Virtual inheritance and constructors in base classes with co Reply with quote



Hi,

I have a question, in a "dreaded diamond" situation, regarding the
following code:

---- Begin code

#include <iostream>

using namespace std;

template <int n>
class Animal
{
protected:
int extremities_;
const int flag_;
public:
Animal(const int &numext) :
extremities_(numext), flag_(1)
{cout << numext << " Extrmsn";}
Animal() {cout << "A NoArgsn";} // Breaks things
// Animal() : flag_(0)
// {cout << "A NoArgsn";} // Uncomment to fix code
};

template class Bird : public virtual Animal<n>
{
public:
Bird() : Animal<n>(2) {cout << "Bird Argsn";}
};

template class CrippledHorse : public virtual Animal<n>
{
public:
CrippledHorse(const int &numext) :
Animal<n>(numext) {cout << "CH Argsn";}
CrippledHorse() {cout << "CH NoArgsn";}
};

template class CrippledPegasus :
public virtual CrippledHorse<n>, public virtual Bird<n>
{
public:
CrippledPegasus(const int &numext) :
Animal<n>(numext) {cout << "CP Argsn";}
};

int main(int argc, char *argv[])
{
CrippledPegasus<0> foo(5);

return 0;
}

---- End code

When I try to compile it with g++ (GCC) 3.4.2 20041017 (Red Hat
3.4.2-6.fc3) I get the following error messages:

tst.cpp: In constructor `Animal<n>::Animal() [with int n = 0]':
tst.cpp:33: instantiated from `CrippledHorse<n>::CrippledHorse() [with
int n = 0]'
tst.cpp:42: instantiated from `CrippledPegasus<n>::CrippledPegasus(const
int&) [with int n = 0]'
tst.cpp:47: instantiated from here
tst.cpp:15: error: uninitialized member `Animal<0>::flag_' with `const'
type `const int'

The templates are not necessary to reproduce the error, but they help
tracing what's going on: after fiddling with it, I think the problem
comes because, for a reason unknown to me, CrippledHorse calls the
Animal constructor without any arguments, which doesn't initialize the
const member variable producing the compiler error.
If my understanding of virtual inheritance is correct, CrippledPegasus
is the responsible of calling the Animal constructor. Thus, neither
CrippledHorse nor Bird should call any of the Animal constructors. In
particular, CrippledHorse should have no reason to deal with Animal()
(the version with no arguments).
However, CrippledHorse does have something to do with Animal() , as
proven by the fact that initializing as in
Animal() : flag_(0)
{cout << "A NoArgsn";} // Uncomment to fix code
fixes the problem.
My puzzlement is even higher when, after running the version of the
code that compiles, I see that the line "A NoArgs" never appears in the
output (as it should be since that constructor isn't supposed to be
called anyway).
So, my question is, is this the standard C++ behavior and my ideas are
wrong? Could this be a problem with the way the compiler implements
things? (sorry, I don't have access to a different compiler yet)
I would sleep much better at night if I didn't have to define Animal()
at all, since that hinders readability because it's never supposed to be
called...
Thanks,

Xavier
Back to top
Thomas Maier-Komor
Guest





PostPosted: Fri Apr 29, 2005 12:21 pm    Post subject: Re: Virtual inheritance and constructors in base classes wit Reply with quote



Xavier wrote:
[ code removed ]
Quote:
The templates are not necessary to reproduce the error, but they help
tracing what's going on: after fiddling with it, I think the problem
comes because, for a reason unknown to me, CrippledHorse calls the
Animal constructor without any arguments, which doesn't initialize the
const member variable producing the compiler error.
If my understanding of virtual inheritance is correct, CrippledPegasus
is the responsible of calling the Animal constructor. Thus, neither
CrippledHorse nor Bird should call any of the Animal constructors. In
particular, CrippledHorse should have no reason to deal with Animal()
(the version with no arguments).
However, CrippledHorse does have something to do with Animal() , as
proven by the fact that initializing as in
Animal() : flag_(0)
{cout << "A NoArgsn";} // Uncomment to fix code
fixes the problem.
My puzzlement is even higher when, after running the version of the
code that compiles, I see that the line "A NoArgs" never appears in the
output (as it should be since that constructor isn't supposed to be
called anyway).
So, my question is, is this the standard C++ behavior and my ideas are
wrong? Could this be a problem with the way the compiler implements
things? (sorry, I don't have access to a different compiler yet)
I would sleep much better at night if I didn't have to define Animal()
at all, since that hinders readability because it's never supposed to be
called...
Thanks,

Xavier

Hi Xavier,

your problem is not at all related to templates. Consider the following
code:
#include
using namespace std;

struct ABC
{
ABC()
{
cout<<"ABC::ABC()" << endl;
}
};

struct A : virtual public ABC
{
A()
: ABC()
{
cout << "A::A()" << endl;
}
};

struct B : virtual public ABC
{
B()
: ABC()
{
cout << "B::B()" << endl;
}
};


struct C : public A, public B
{
C()
: A()
, B()
{
cout << "C::C()" << endl;
}
};

int main()
{
C c;
return 0;
}


It will print:
ABC::ABC()
A::A()
B::B()
C::C()


The compiler is responsible that the virtual base class gets constructed
exactly once. But this still means that every derived class that
has a virtual base class needs to call the base class' constructor.
Here A and B call ABC's constructor, but it only gets executed once.
C does not call ABC's constructor and it also must not call it, because
it is not derived directly from it.

Hope that helps.
Consider reading ISO/IEC 14882 chapter 10.


Cheers,

Tom

Back to top
Thomas Maier-Komor
Guest





PostPosted: Fri Apr 29, 2005 12:35 pm    Post subject: Re: Virtual inheritance and constructors in base classes wit Reply with quote



Thomas Maier-Komor wrote:

Quote:
Consider reading ISO/IEC 14882 chapter 10.

and even more appropriate sections 12.6 and 12.7

Back to top
Kanenas
Guest





PostPosted: Mon May 30, 2005 3:12 am    Post subject: Re: Virtual inheritance and constructors in base classes wit Reply with quote

On Fri, 29 Apr 2005 11:54:20 +0200, Xavier <dont (AT) like_sp (DOT) am> wrote:

Quote:
Hi,

I have a question, in a "dreaded diamond" situation, regarding the
following code:
[...]

When I try to compile it with g++ (GCC) 3.4.2 20041017 (Red Hat
3.4.2-6.fc3) I get the following error messages:

[...]


Considering that g++ 3.3.2 on OpenBSD 3.6 compiles the example with no
errors and what Stroustrup has to say in section 15.2.4.1:
"For example, the language ensures that a constructor of a
virtual base is called exactly once. The constructor of a
virtual base is invoked (implicitly or explicitly) from the
constructor for the complete object (the constructor for the
most derived class)."
I'd say it's a compiler issue, not a language issue.

Quote:
However, CrippledHorse does have something to do with Animal() , as
proven by the fact that initializing as in
Animal() : flag_(0)
{cout << "A NoArgsn";} // Uncomment to fix code
fixes the problem.
My puzzlement is even higher when, after running the version of the
code that compiles, I see that the line "A NoArgs" never appears in the
output (as it should be since that constructor isn't supposed to be
called anyway).

Sounds like the bytecode g++ 3.4.2 emits is correct; the error is
probably just in the overload-resolution components of g++ (or the
components which check that const variables get initialized or
whatever spits out the error).

Quote:
So, my question is, is this the standard C++ behavior and my ideas are
wrong? Could this be a problem with the way the compiler implements
things? (sorry, I don't have access to a different compiler yet)

You're right. The error from g++ 3.4.2 is non-standard behavior.
Fortunately, you found a workaround.

Kanenas

Back to top
Kanenas
Guest





PostPosted: Mon May 30, 2005 3:40 am    Post subject: Re: Virtual inheritance and constructors in base classes wit Reply with quote

On Fri, 29 Apr 2005 14:21:58 +0200, Thomas Maier-Komor
<maierkom (AT) lpr (DOT) no-spam.e-technik.tu-muenchen.de> wrote:

[...]
Quote:
your problem is not at all related to templates. Consider the following
code:

As Xavier said:
Quote:
The templates are not necessary to reproduce the error, but they help
tracing what's going on:


The compiler is responsible that the virtual base class gets constructed
exactly once. But this still means that every derived class that
has a virtual base class needs to call the base class' constructor.
Here A and B call ABC's constructor, but it only gets executed once.

Construction generally consists of allocating space and then invoking
a constructor, so the statement that a virtual base's constructor
needs to be called (or rather, invoked) more than once is a
contradiction. Considering that to invoke a constructor will execute
it, it's contradictory to say that ABC's constructor is called (or
rather, invoked) twice when constructing a C yet is executed exactly
once.

Quote:
C does not call ABC's constructor and it also must not call it, because
it is not derived directly from it.

A class can (explicity or implicitly) invoke the constructor for a

virtual base class in an initializer list even if not a direct
descendent; indeed, it must.

As you later suggested, I looked at section 12.6 and found:
12.6.2.5:
"Initialization shall proceed in the following order:
-- First, and only for the constructor of the most derived class as
described below, virtual base classes shall be initialized in the
order they appear on a depth-first left-to-right traversal of the
directed acyclic graph of base classes, where "left-to-right" is the
order of appearance of the base class names in the derived class
base-specifier-list."

This, too, implies the constructors for A and B will not invoke ABC's
constructor when constructing a C.

Kanenas

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language (comp.lang.c++) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.