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 << " Extrms\n";}
Animal() {cout << "A NoArgs\n";} // Breaks things
// Animal() : flag_(0)
// {cout << "A NoArgs\n";} // Uncomment to fix code
};
template <int n>
class Bird : public virtual Animal<n>
{
public:
Bird() : Animal<n>(2) {cout << "Bird Args\n";}
};
template <int n>
class CrippledHorse : public virtual Animal<n>
{
public:
CrippledHorse(const int &numext) :
Animal<n>(numext) {cout << "CH Args\n";}
CrippledHorse() {cout << "CH NoArgs\n";}
};
template <int n>
class CrippledPegasus :
public virtual CrippledHorse<n>, public virtual Bird<n>
{
public:
CrippledPegasus(const int &numext) :
Animal<n>(numext) {cout << "CP Args\n";}
};
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 NoArgs\n";} // 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 4 4586
Xavier wrote:
[ code removed ] 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 NoArgs\n";} // 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 <iostream>
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
Thomas Maier-Komor wrote: Consider reading ISO/IEC 14882 chapter 10.
and even more appropriate sections 12.6 and 12.7
On Fri, 29 Apr 2005 11:54:20 +0200, Xavier <dont@like_sp.am> wrote: 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.
However, CrippledHorse does have something to do with Animal() , as proven by the fact that initializing as in Animal() : flag_(0) {cout << "A NoArgs\n";} // 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).
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
On Fri, 29 Apr 2005 14:21:58 +0200, Thomas Maier-Komor
<ma******@lpr.no-spam.e-technik.tu-muenchen.de> wrote:
[...] your problem is not at all related to templates. Consider the following code:
As Xavier said: 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.
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 This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Alexander Stippler |
last post by:
I've got an inheritance structure with two coupled "dreaded diamonds" like
shown below:
A
/ \
/ \
B C
\ / \
\ / \
D E
\ /
|
by: Ben Blank |
last post by:
I'm writing a family of classes which all inherit most of their methods and
code (including constructors) from a single base class. When attempting to
instance one of the derived classes using...
|
by: Marcin Kalicinski |
last post by:
Hi,
Having the following program:
#include <iostream>
struct A
{
A() { std::cout << "A::A()\n"; }
A(const A &) { std::cout << "A::A(const A &)\n"; }
|
by: mijobee |
last post by:
I'm very new to c++ and just writing some code to learn. I've run into
a problem, with a javaish design, and want to know if there is any
possible solution without modifying the design. I've read...
|
by: toton |
last post by:
Hi,
I want a few of my class to overload from a base class, where the
base class contains common functionality. This is to avoid repetition
of code, and may be reducing amount of code in binary,...
|
by: Markus Svilans |
last post by:
Hello,
My question involves virtual functions and inheritance.
Suppose we have a class structure, that consists of "data" classes, and
"processor" classes. The data classes are derived from...
|
by: BeautifulMind |
last post by:
In case of inheritence the order of execution of constructors is in
the order of derivation and order of destructor execution is in
reverse order of derivation.
Is this case also true in case...
|
by: Jess |
last post by:
Hello,
If I have a class that has virtual but non-pure declarations, like
class A{
virtual void f();
};
Then is A still an abstract class? Do I have to have "virtual void
f() = 0;"...
|
by: =?Utf-8?B?Zmplcm9uaW1v?= |
last post by:
Hi all,
As I mentioned in a previous thread (see 'Dbghelp, symbols and templates' in
microsoft.public.windbg), we created a powerful symbol engine using dbghelp
to dump the contents of the stack...
|
by: Charles Arthur |
last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
|
by: aa123db |
last post by:
Variable and constants
Use var or let for variables and const fror constants.
Var foo ='bar';
Let foo ='bar';const baz ='bar';
Functions
function $name$ ($parameters$) {
}
...
|
by: ryjfgjl |
last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
|
by: ryjfgjl |
last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
|
by: BarryA |
last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
|
by: Hystou |
last post by:
There are some requirements for setting up RAID:
1. The motherboard and BIOS support RAID configuration.
2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
| |