Home > Software design >  C , child with both parents having a same ancestor
C , child with both parents having a same ancestor

Time:01-24

I'm having trouble with C classes and inheritance right now...

Let's say we have

Class A {
A(string name);
    ~A();
    void func(void);
}
Class B : public A {
    B(string name);
    ~B();
    ...
}
Class C : public A {
    C(string name);
    ~C();
    ...
}
Class D : public B, public D {
    D(string name);
    ~D();
    ...
}

Whenever I create D, it calls the constructor for B and the one for C which results in multiple instances of A. The compiler then says it doesn't know which "func" it should call, the one from B or the one from C.

I would like to know how to call A constructor ONLY ONCE and then use it to build B and C.

I already tried using B::func() to be able to call func() but has I must have a cout in the class A builder. It results in wrong output.

CodePudding user response:

This is called the diamond inheritance pattern.
In order to avoid having 2 instances of A in D, you need to use virtual inheritance.
When classes e.g. B virtually inherit A, it means that A will be present only once in a class derived from those classes.
Note: in this case it is the responsibility of the most derived class to initialize the virtual base(s) - as shown below.

The output from the following code demonstrates it:

#include <iostream>
#include <string>

class A {
public:
    A(std::string const & name) { std::cout << "A::A\n"; };
    ~A() {};
    void func(void);
};
//--------vvvvvvv-----------
class B : virtual public A {
public:
    B(std::string const& name) : A(name) { std::cout << "B::B\n"; };
    ~B() {};
};
//--------vvvvvvv-----------
class C : virtual public A {
public:
    C(std::string const& name) : A(name) { std::cout << "C::C\n"; };
    ~C() {};
};
class D : public B, public C {
public:
//-------------------------------vvvvvvv---------------------------------------------
    D(std::string const& name) : A(name), B(name), C(name) { std::cout << "D::D\n"; };
    ~D() {};
};

int main()
{
    D d("aaa");
}

Output:

A::A
B::B
C::C
D::D

I.e. A is present once in D.

Note that if you remove the virtual keyword, the output will be:

A::A
B::B
A::A
C::C
D::D

I.e. A is present twice in D (as you observed).


Some side notes:

  1. Better to avoid using namespace std - see here Why is "using namespace std;" considered bad practice?.
  2. Your code contains many typos: Class should be class, missing ; at the end of classes.
  3. You constructors can accept the name by const & as demonstrated in my code, to avoid copy.
  • Related