c++inheritancemultiple-inheritancediamond-problem

Make a child class inherit specific attributes from two different parent classes?


I have a problem with a Diamond inheritance exercise.

I have one base class A. Here is its constructor :

A::A(std::string name) : _hp(10), _ep(10), _ad(0)
{
    std::cout << "A object created !" << std::endl;
    return ;
}

Then, I have two parent classes B and C. Here are their constructors:

B::B(std::string name) : A(name)
{

    std::cout << "B object created !" << std::endl;
    this->_hp = 100;
    this->_ep = 50;
    this->_ad = 20;
    return;
}

C::C(std::string name) : A(name)
{
    std::cout << "C object created !" << std::endl;
    this->_hp = 100;
    this->_ep = 100;
    this->_ad = 30;
    return ;
}

And finally, I have one child class . Here is its constructor:

D::D(std::string name) : A(name + "_comes_from_A")
{
    this->_name = name;
    std::cout << "D object created !" << std::endl;
    this->_hp = C::_hp;
    this->_ep = B::_ep;
    this->_ad = C::_ad;
    return;
}

The D class inherits from class B and C. The B and C classes both inherits from class A. I did something like this :

class A
{
    // code here

    protected:

    std::string _name;
    int         _hp;
    int         _ep;
    int         _ad;
};

class B : virtual public A
{
    // code here
};

class C : virtual public A
{
    // code here
};

class D : public B, public C
{
    // code here
};

As it can be noticed in the constructor of D class, I want it to inherits _ep from the B class (50) and _hp and _ad from the C class (100 and 30).

However, if I check the value of the _ep value in my D class, (with something like this for instance) :

std::cout << "ENERGY POINTS " << this->_ep << std::endl;

it is always equal to 100 (which comes from the C class).

I have noticed it depends on the order in which I handle inheritance for D class but I would like to be able to access values of any of the parent class from my child class. Can someone help me with that ? Thanks in advance!

MINIMAL REPRODUCIBLE EXAMPLE :

class A
{
    public :

    A(){
        return ;
    };
    A(std::string name) : _hp(10), _ep(10), _ad(0){
        std::cout << "A object created !" << std::endl;
        return ;
    };
    ~A(){
        std::cout << "A object " << this->_name << " destroyed." << std::endl;
        return ;
    };

    protected:

    std::string _name;
    int         _hp;
    int         _ep;
    int         _ad;
};

class B : virtual public A
{
    public :

    B(){
        return ;
    };
    B(std::string name) : A(name){
        std::cout << "B object created !" << std::endl;
        this->_hp = 100;
        this->_ep = 50;
        this->_ad = 20;
        return ;
    };
    ~B(){
        std::cout << "B object " << this->_name << " destroyed." << std::endl;
        return ;
    };
};

class C : virtual public A
{
    public :

    C(){
        return ;
    };
    C(std::string name) : A(name){
        std::cout << "C object created !" << std::endl;
        this->_hp = 100;
        this->_ep = 100;
        this->_ad = 30;
        return ;
    };
    ~C(){
         std::cout << "C object " << this->_name << " destroyed." << std::endl;
    return ;
    };
};

class D : public B, public C
{
    public :

    D(){
        return ;
    };
    D(std::string name) : A(name + "_comes_from_a"){
        this->_name = name;
        std::cout << "D object created !" << std::endl;
        this->_hp = C::_hp;
        this->_ep = B::_ep;
        this->_ad = C::_ad;
        std::cout << "HIT POINTS " << this->_hp << std::endl;
        std::cout << "ENERGY POINTS " << this->_ep << std::endl;
        std::cout << "ATTACK DAMAGE " << this->_ad << std::endl;
        return;
     }
     ~D(){
        std::cout << "D object " << this->_name << " destroyed." << std::endl;
        return ;
     };
};

int main(void)
{
     D  obj_D("TEST");
     return (0);
}

Solution

  • Okay, I got my program to work properly. Maybe I didn't explain well what I wanted to do, but I'm posting my solution here.
    There are 4 classes A, B, C and D. They all have _hp, _ep and _ad variables.
    D inherits from B AND C, which in turn inherit from A.
             A
           /     \
          B     C
           \      /
              D
    I wanted my D class to take :

    Here is the minimal reproducible example of the code that worked for me :

    # include <iostream>
    # include <string>
    
    class A
    {
        public :
    
            A(){
                return ;
            };
    
            A(std::string name) : _hp(10), _ep(10), _ad(0){
                std::cout << "A object created !" << std::endl;
                return ;
            };
    
            ~A(){
                std::cout << "A object " << this->_name << " destroyed." << std::endl;
                return ;
            };
    
        protected:
    
            std::string _name;
            int         _hp;
            int         _ep;
            int         _ad;
    };
    
    class B : virtual public A
    {
        public :
    
            B(){
                return ;
            };
    
            B(std::string name) : A(name){
                std::cout << "B object created !" << std::endl;
                this->_hp = 100;
                this->_ep = 50;
                this->_ad = 20;
                return ;
            };
    
            ~B(){
                std::cout << "B object " << this->_name << " destroyed." << std::endl;
                return ;
            };
    
            static const int    EP = 50;
    };
    
    class C : virtual public A
    {
        public :
    
            C(){
                return ;
            };
    
            C(std::string name) : A(name){
                std::cout << "C object created !" << std::endl;
                this->_hp = 100;
                this->_ep = 100;
                this->_ad = 30;
                return ;
            };
    
            ~C(){
                std::cout << "C object " << this->_name << " destroyed." << std::endl;
                return ;
            };
    
            static const int    HP = 100;
            static const int    AD = 30;
    };
    
    class D : public B, public C
    {
        public :
    
            D(){
                return ;
            };
            D(std::string name) : A(name + "_comes_from_a"){
                this->_name = name;
                std::cout << "D object created !" << std::endl;
                this->_hp = C::HP;
                this->_ep = B::EP;
                this->_ad = C::AD;
                std::cout << "HIT POINTS " << this->_hp << std::endl;
                std::cout << "ENERGY POINTS " << this->_ep << std::endl;
                std::cout << "ATTACK DAMAGE " << this->_ad << std::endl;
                return;
            }
    
            ~D(){
                std::cout << "D object " << this->_name << " destroyed." << std::endl;
                return ;
            };
    };
    
    int main(void)
    {
        D   obj_D("TEST");
        return (0);
    }
    

    The difference with the example that I posted in the question is that I declared static const int variables (HP, EP and AD) in my B and C classes. Thus, I am now able to access the values either from B or C classes in the constructor of class D. Typically, what I did earlier was wrong :

        // before (not working)
        this->_hp = C::_hp;
        this->_ep = B::_ep;
        this->_ad = C::_ad;   
    
        // now (working)
        this->_hp = C::HP;
        this->_ep = B::EP;
        this->_ad = C::AD;
    

    The output is now :

    A object created !
    D object created !
    HIT POINTS 100
    ENERGY POINTS 50
    ATTACK DAMAGE 30
    D object TEST destroyed.
    C object TEST destroyed.
    B object TEST destroyed.
    A object TEST destroyed.