By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,797 Members | 1,315 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,797 IT Pros & Developers. It's quick & easy.

diamond inheritance, constr. question

P: n/a
Hello C++ NG,

I encountered a strange behaviour in this code

#include <iostream>
#include <cstdlib>
#include <string>

using std::cout;
using std::endl;

#define virtual_Y
#define virtual_X

class A
{
public:
A(std::string s) { cout << (s+">A") << endl; } // <<<< 1
static std::string name;
};

std::string A::name = "<class A>";

class X : public virtual_X A
{
public:
X(std::string s) : A(s+">X") {}
};

class Y : public virtual_Y A
{
public:
Y(std::string s) : A(s+">Y") {}
};

class XX : public X
{
public:
XX(std::string s) : X(s+">XX") {}
};

class YY : public Y
{
public:
YY(std::string s) : Y(s+">YY") {}
};

class C : public XX, public YY
{
public:
C() : XX("C"), YY("C") {}
};

int main()
{
// are the same
cout << A::name << endl;
cout << C::XX::X::A::name << endl;
return EXIT_SUCCESS;
}

it compiles and runs fine without virtual inheritance
I do get the following hierarchy

A A
\ /
B C
\ /
D
what is strange, when I change

#define virtual_Y virtual
#define virtual_X virtual

and get this diamond hierarchy

A
/ \
B C
\ /
D

then my compiler (gcc-Version 3.3.1) tells me

mond:/pool/PROG/C++/C++/multiple # g++ -o main main.cpp -Wall -g
main.cpp: In constructor `XX::XX(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)':
main.cpp:35: error: no matching function for call to `A::A()'
main.cpp:12: error: candidates are: A::A(const A&)
main.cpp:14: error: A::A(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)
main.cpp: In constructor `YY::YY(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)':
main.cpp:41: error: no matching function for call to `A::A()'
main.cpp:12: error: candidates are: A::A(const A&)
main.cpp:14: error: A::A(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)
main.cpp: In constructor `C::C()':
main.cpp:47: error: no matching function for call to `A::A()'
main.cpp:12: error: candidates are: A::A(const A&)
main.cpp:14: error: A::A(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)

the bottom line is, it cannot find the approproite constructor
when I provide a default costructor then it compiles
A(std::string s="") { cout << (s+">A") << endl; } // <<<< 1

what is going on here?

Regards, Daniel

Jan 13 '06 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Schüle Daniel wrote:
I encountered a strange behaviour in this code

#include <iostream>
#include <cstdlib>
#include <string>

using std::cout;
using std::endl;

#define virtual_Y
#define virtual_X

class A
{
public:
A(std::string s) { cout << (s+">A") << endl; } // <<<< 1
static std::string name;
};

std::string A::name = "<class A>";

class X : public virtual_X A
{
public:
X(std::string s) : A(s+">X") {}
};

class Y : public virtual_Y A
{
public:
Y(std::string s) : A(s+">Y") {}
};

class XX : public X
{
public:
XX(std::string s) : X(s+">XX") {}
};

class YY : public Y
{
public:
YY(std::string s) : Y(s+">YY") {}
};

class C : public XX, public YY
{
public:
C() : XX("C"), YY("C") {}
};

int main()
{
// are the same
cout << A::name << endl;
cout << C::XX::X::A::name << endl;
return EXIT_SUCCESS;
}

it compiles and runs fine without virtual inheritance
I do get the following hierarchy

A A
\ /
B C
\ /
D
Actually, I believe it's

A A
\ /
X Y
\ /
XX YY
\ /
C

what is strange, when I change

#define virtual_Y virtual
#define virtual_X virtual

and get this diamond hierarchy

A
/ \
B C
\ /
D
No, I believe you get

A
/ \
X Y
| |
XX YY
\ /
C

then my compiler (gcc-Version 3.3.1) tells me

mond:/pool/PROG/C++/C++/multiple # g++ -o main main.cpp -Wall -g
main.cpp: In constructor `XX::XX(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)':
main.cpp:35: error: no matching function for call to `A::A()'
main.cpp:12: error: candidates are: A::A(const A&)
main.cpp:14: error: A::A(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)
main.cpp: In constructor `YY::YY(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)':
main.cpp:41: error: no matching function for call to `A::A()'
main.cpp:12: error: candidates are: A::A(const A&)
main.cpp:14: error: A::A(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)
main.cpp: In constructor `C::C()':
main.cpp:47: error: no matching function for call to `A::A()'
main.cpp:12: error: candidates are: A::A(const A&)
main.cpp:14: error: A::A(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)

the bottom line is, it cannot find the approproite constructor
when I provide a default costructor then it compiles
A(std::string s="") { cout << (s+">A") << endl; } // <<<< 1

what is going on here?


Virtual base class subobjects are initialised by the most derived class'
constructor. If you do not _explicitly_ specify its initialisation in
the most derived class' c-tor's initialiser list, the default c-tor of
the virtual base class is used. If there is no default c-tor, the program
is ill-formed.

You've encountered this specific rule. You either need to provide the
default c-tor in 'A' when 'A' is virtually inherited, or you need to add
the initialiser for it in 'C':

class C : public XX, public YY
{
public:
C() : A("C"), XX("C"), YY("C") {}
};

V
Jan 13 '06 #2

P: n/a
Schüle Daniel wrote:
Hello C++ NG, [snip]
A
/ \
B C
\ /
D

then my compiler (gcc-Version 3.3.1) tells me

mond:/pool/PROG/C++/C++/multiple # g++ -o main main.cpp -Wall -g
main.cpp: In constructor `XX::XX(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)':
main.cpp:35: error: no matching function for call to `A::A()'
main.cpp:12: error: candidates are: A::A(const A&)
main.cpp:14: error: A::A(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)
main.cpp: In constructor `YY::YY(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)':
main.cpp:41: error: no matching function for call to `A::A()'
main.cpp:12: error: candidates are: A::A(const A&)
main.cpp:14: error: A::A(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)
main.cpp: In constructor `C::C()':
main.cpp:47: error: no matching function for call to `A::A()'
main.cpp:12: error: candidates are: A::A(const A&)
main.cpp:14: error: A::A(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >)

the bottom line is, it cannot find the approproite constructor
when I provide a default costructor then it compiles
A(std::string s="") { cout << (s+">A") << endl; } // <<<< 1

what is going on here?

Regards, Daniel


Virtual base must be initialized separetly in all derived classes,
this is the price one must pay for it.
Consider the diamond above and what you have implemented yourself:

B::B(std::string s) : A(s+">B") {}
C::C(std::string s) : A(s+">C") {}

In the constructor of D how should A be initialized, via B or via C?
Remember: A can be constructed only once
and the compiler can't make the choice, thus you'll need to tell him.
D::D(std::string s): A("D"), B("D"), C("D") {}

Regards, Stephan
br****@osb-systems.com
Open source rating and billing engine for communication networks.

Jan 13 '06 #3

P: n/a
[..]
Virtual base must be initialized separetly in all derived classes,
this is the price one must pay for it.
Consider the diamond above and what you have implemented yourself:

B::B(std::string s) : A(s+">B") {}
C::C(std::string s) : A(s+">C") {}

In the constructor of D how should A be initialized, via B or via C?
Remember: A can be constructed only once
and the compiler can't make the choice, thus you'll need to tell him.
D::D(std::string s): A("D"), B("D"), C("D") {}


yes, this makes sense

so the rule would be ..
either the class which merges two branches of diamond together
should call the virtual base constructor explicitly or virtual
base class should have default constructor

Regards, Daniel

Jan 13 '06 #4

P: n/a
Schüle Daniel wrote:
yes, this makes sense

so the rule would be ..
either the class which merges two branches of diamond together
should call the virtual base constructor explicitly or virtual
base class should have default constructor


No, virtual base classes must be initialized in ALL derived classes.
Somebody might provide a rationale for this rule. With
A
/ \
B C
\ / \
D CC
|
E

E must initialize A in its constructors:
class E : public class D {
public:
// E() {}
// ^ errror: no default constructor for A
E() : A("E") {}
};
and similar for class CC.

Regards, Stephan
br****@osb-systems.com
Open source rating and billing engine for communication networks.

Jan 14 '06 #5

This discussion thread is closed

Replies have been disabled for this discussion.