Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > diamond inheritance, constr. question

Reply
Thread Tools

diamond inheritance, constr. question

 
 
Victor Bazarov
Guest
Posts: n/a
 
      01-13-2006
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
 
Reply With Quote
 
 
 
 
=?iso-8859-1?q?Stephan_Br=F6nnimann?=
Guest
Posts: n/a
 
      01-13-2006
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:(std::string s): A("D"), B("D"), C("D") {}

Regards, Stephan
http://www.velocityreviews.com/forums/(E-Mail Removed)
Open source rating and billing engine for communication networks.

 
Reply With Quote
 
 
 
 
=?ISO-8859-1?Q?Sch=FCle_Daniel?=
Guest
Posts: n/a
 
      01-13-2006
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

 
Reply With Quote
 
=?ISO-8859-1?Q?Sch=FCle_Daniel?=
Guest
Posts: n/a
 
      01-13-2006
[..]

> 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:(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

 
Reply With Quote
 
=?iso-8859-1?q?Stephan_Br=F6nnimann?=
Guest
Posts: n/a
 
      01-14-2006
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
(E-Mail Removed)
Open source rating and billing engine for communication networks.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
PRINTING DIAMOND SHAPE WITH LOOPS! Jay Dean Java 57 12-10-2013 02:14 AM
Diamond Stealth X550 Silverstrand Front Page News 0 02-02-2006 01:17 PM
MSI P4N Diamond NF4-SLI Intel Edition Motherboard Review Silverstrand Front Page News 0 09-14-2005 08:48 PM
A question about the diamond inheritance Tony Johansson C++ 3 08-21-2005 06:10 PM
Re: Diamond Supra Express 56e Pro problems. Michael Klontzas Computer Support 0 06-23-2003 11:05 PM



Advertisments