Reputation: 569
Can someone help me understand how a class that inherits from multiple classes can retain certain attribute values from one class and other certain attribute values from another.
(and how would one do so for certain functions as well)
Here is a bit of code to describe the problem.
It's a situation where there is a diamond inheritance structure:
------------- Base
----------/---------------\
-------/--------------------\
--- Mother-------------Father
---\ -----------------------/
------\ ------------------/
---------\ -------------/
------------ Child
The goal is to inherit from both the Father
class & the Mother
class (& evidently from the Base
class) but to retain the y
value of the Father
and the z
value from the Mother
. I just don't know how to do that.
I believe that the problem with the following code is that the order in which the constructors are called make it so that the Father
constructor overwrites the z
value that the Mother
constructor right before it initialized.
I'm thinking that I might have to make a special private
/protected
Father
constructor that doesn't initialize the z
and a special private
/protected
Mother
constructor that doesn't initialize the y
and explicitly call those constructors.
But idk if that's the right way of doing it or if there's a better way. Does anyone know a better way ?
#include <iostream>
class Base {
protected:
int x;
int y;
int z;
public:
Base(void) : x(0) {}
};
/* — — — — — — — — — — — — — — — — — — — — */
class Father
: public virtual Base {
public:
Father(void) : Base() {
y = 1;
z = 1;
}
};
/* — — — — — — — — — — — — — — — — — — — — */
class Mother
: public virtual Base {
public:
Mother(void) : Base() {
y = 2;
z = 2;
}
};
/* — — — — — — — — — — — — — — — — — — — — */
class Child
: public Mother, public Father {
public:
Child(void) : Base() {
y = Father::y;
z = Mother::z;
}
int getX() { return x; };
int getY() { return y; };
int getZ() { return z; };
};
/* — — — — — — — — — — — — — — — — — — — — */
int main() {
Child newborn;
std::cout << newborn.getX() << std::endl
<< newborn.getY() << std::endl
<< newborn.getZ() << std::endl;
return (0);
}
/* — — — — — — — — — — — — — — — — — — — — */
Output:
0
1
1
——— VS ———
Desired Output:
0
1
2
Upvotes: 2
Views: 6257
Reputation: 6805
You can't do it this way.
The virtual inheritance is aimed to not duplicate the members.
Knowing this:
Child::x
, Mother::x
and Father::x
are exactly the same variableChild::y
, Mother::y
and Father::y
are exactly the same variableChild::z
, Mother::z
and Father::z
are exactly the same variableThese are just three ways to access the same variable on the memory stack. So when you writes y = Father::y;
, it is exactly the same as if you had written y = y;
, and so on for the other variables.
If you really want to do that without changing your design, perhaps you can store in Father
and in Mother
an extra variable which contains the preset you want and just give it to Child
through scope resolution.
Father
, Mother
and Child
could look like:
class Father : public virtual Base
{
protected:
int preset;
public:
Father() : preset(1)
{
y = preset;
z = preset;
}
};
class Mother : public virtual Base
{
protected:
int preset;
public:
Mother() : preset(2)
{
y = preset;
z = preset;
}
};
class Child : public Mother, public Father
{
public:
Child()
{
y = Father::preset;
z = Mother::preset;
}
int getX() const {return x;}
int getY() const {return y;}
int getZ() const {return z;}
};
And it should do the trick with few changes.
To conclude, I would say that for each problem that requires multiple inheritance, there is at least one other solution (a better design) which does not imply multiple inheritance (This is only my opinion).
So I would advise you to reconsider your design instead of using the workaround I proposed here.
Upvotes: 3