X
Xavier
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
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