Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 488
user815129 Avatar asked Jun 25 '11 08:06

user815129


2 Answers

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.

like image 158
Puppy Avatar answered Sep 18 '22 01:09

Puppy


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;
};
like image 21
BЈовић Avatar answered Sep 18 '22 01:09

BЈовић