diamond inheritance, constr. question

Discussion in 'C++' started by Victor Bazarov, Jan 13, 2006.

  1. 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
    Victor Bazarov, Jan 13, 2006
    #1
    1. Advertising

  2. 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

    Open source rating and billing engine for communication networks.
    =?iso-8859-1?q?Stephan_Br=F6nnimann?=, Jan 13, 2006
    #2
    1. Advertising

  3. 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
    =?ISO-8859-1?Q?Sch=FCle_Daniel?=, Jan 13, 2006
    #3
  4. [..]

    > 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
    =?ISO-8859-1?Q?Sch=FCle_Daniel?=, Jan 13, 2006
    #4
  5. 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

    Open source rating and billing engine for communication networks.
    =?iso-8859-1?q?Stephan_Br=F6nnimann?=, Jan 14, 2006
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alexander Stippler

    virtual inheritance / dreaded diamond problem

    Alexander Stippler, Jul 14, 2003, in forum: C++
    Replies:
    0
    Views:
    1,867
    Alexander Stippler
    Jul 14, 2003
  2. Alexander Stippler

    virtual inheritance / dreaded diamond again

    Alexander Stippler, Aug 26, 2003, in forum: C++
    Replies:
    1
    Views:
    380
    Ron Natalie
    Aug 26, 2003
  3. Tom
    Replies:
    3
    Views:
    492
  4. =?ISO-8859-2?Q?Nagy_L=E1szl=F3_Zsolt?=

    Re: [Boa Constr] Download of 0.2.7 Available

    =?ISO-8859-2?Q?Nagy_L=E1szl=F3_Zsolt?=, Dec 4, 2003, in forum: Python
    Replies:
    3
    Views:
    372
    Rene Aguirre
    Dec 5, 2003
  5. Tony Johansson
    Replies:
    3
    Views:
    328
    Masrur Hossain
    Aug 21, 2005
Loading...

Share This Page