multiple inheritance and data members
I never used multiple inheritance and stumbled into a design problem I never faced..
class A {
//..methods..
}
class B : public A {
int b;
//...methods..
}
class C : public A {
int c1,c2;
}
class D : public B,public C {
}
Here's the classical diamond. The fact is that C
is really just an A
with two extra ints. and D
is really just an aggregation of B
and C
but I feel like multiple inheritance was not designed to make things like these. Or that there may be other best practices to do this.
The reason why im trying to implement multiple inheritance is that I want to write a function like void func(A*)
and pass it either a A
or D
class pointer. My ingenuous attempt is to make a simple cast:
void func(A* a) { // <-- I call this with a A or D pointer
// ..do something with A members..
if(is_the_case) { // <-- Im sure the passed "a" pointer is actually a *D
D* d = (D*)a;
// ..do something with the extra 2 ints provided by the C class..
}
}
Doesn't work.. Compiles fine, but I have a really strange behaviour when if(is_the_case)
is executed, clearing that 2 extra ints c1
and c2
, clears also b
(inherithed by B
).
I remebered about the diamond problem,开发者_运维技巧 but here there is only one B
(and 2 A
) in the hierarchy, so I don't understand why b
gets cleared as well. Just to try, I used public virtual in B
and C
declaration. Now every cast is a compile error unless I use a dynamic_cast
..
Can someone make it clear what's happening behind the scenes? What is the best practice to do it, considering there are other classes like:
class E : public A {
int e;
//..methods..
}
class F : public E,public C {
}
That is, other classes that are just an aggregation of a class derived from A
+ two extra ints inherited by C
and that can be passed to a funcion that takes *A
Thanks, did my best to be as clear as possible..
Your code is working because you used a C-style cast, which can be a reinterpret_cast
, and it's my understanding that you can reinterpret_cast
between any two pointer types, even if it doesn't make sense. You must use a dynamic_cast
when casting up from a multiply inherited base to a more derived class. A static_cast
would yield a compile-time error. In fact, dynamic_cast
does both jobs at once.
void func(A* a) { // <-- I call this with a A or D pointer
// ..do something with A members..
if(D* d = dynamic_cast<D*>(a)) { // a definitely points to a D
// and we got a guaranteed good pointer too
}
}
This is an excellent example of why C-style casts should be avoided.
You can read about multiple inheritance here.
What you need to do is virtually inherit next classes :
class B : virtual public A {
int b;
//...methods..
};
class C : virtual public A {
int c1,c2;
};
I don't know why you're seeing this behaviour. As noted in comments, you code as described shouldn't compile.
Is there a design issue? Yes. Don't explicitly make choices based on querying an object's type. That's what virtual functions are for.
class A
{
public:
virtual void prepare_for_list_insertion() {}
};
class B : public A
{
int b;
};
class C : public A
{
private:
int c1, c2;
protected:
void clear() { c1 = c2 = 0; }
};
class D : public B, public C
{
public:
void prepare_for_list_insertion()
{
clear();
}
};
void func(A* a)
{
a->prepare_for_list_insertion();
}
int main()
{
A a;
func(&a); // calls A::prepare_for_list_insertion
D d;
// You need a cast to disambiguate the A base - either will do.
func(static_cast<C*>(&d)); // calls D::prepare_for_list_insertion
func(static_cast<B*>(&d)); // calls D::prepare_for_list_insertion
}
精彩评论