开发者

How to align pointers when dealing with multiple-inheritance?

开发者 https://www.devze.com 2023-02-25 12:35 出处:网络
Say we have a concrete class A, and an abstract class B. Consider a concrete C, that inherits from both A and B, and implements B:

Say we have a concrete class A, and an abstract class B.

Consider a concrete C, that inherits from both A and B, and implements B:

class C : public A, public B  
{  
/* implementation of B and specific stuff that belongs to C */  
};

Now I define a function which signature is void foo(B* b);开发者_开发技巧

This is my code, I can assume that every pointers to B are both A and B. In foo's definition, how to get a pointer to A? A nasty but working trick is to align back pointers like so:

void foo(B* b)  
{  
    A* a = reinterpret_cast<A*>(reinterpret_cast<char*>(b) - sizeof(A));
    // now I can use all the stuff from A  
}

Keep in mind that C does not have a super type and actually, there are many classes akin to C which only are A and B. Feel free to question both my logic and this sample of design as well but the question is only concerning pointers alignment.


void foo(B* b)  
{  
    //A* a = reinterpret_cast<A*>(reinterpret_cast<char*>(b) - sizeof(A)); // undefined behaviour!!!!
    A* a = dynamic_cast<A*>(b);
    if (a)
    {
       // now I can use all the stuff from A  
    }
    else
    {
       // that was something else, not descended from A
    }
}

Forgot to say: in order to make work dynamic cast both A and B should have virtual function(s) or at least virtual destructors. Otherwise there is no legal way to do that type conversion.


Having a huge set of unrelated classes that both derive from A and B is a very strange design. If there's something that makes A and B always be "used together" you could either merge them or introduce a shim class that only derives from them and then only derive from that class:

class Shim : A, B {};

class DerivedX : Shim {};

and in the latter case you just use static_cast to first downcast from A or B to Shim* and then C++ it will implicitly convert the Shim* pointer to the other class.


If you want to use the functionality of both class A and Class B in your function then you should modify the function to receive C pointers:

void foo(C* c);

And in general you are wrong with you assumption that "every B is an A as well". You could create classes derived from you B interface and not derived from Class A, that's why the compiler won't know that in your specific case "every B is an A".


Expanding on sharptooth's answer (and entering it as an answer, because I can't get formatted code into a comment), you can still use the shim:

class Shim : public virtual A, public virtual B {};

Then:

class Derived1 : public Shim, public virtual A, public virtual B1
{
};

class Derived2 : public Shim, public virtual A, public virtual B2
{
};

B1 and B2 must derive virtually from B.

But I suspect that if you always need to implement both A and B, you should create a single interface with both, either by inheriting, or coalising both into a single class; your B1 and B2 would inherit from that. (The solution with dynamic_cast, of course, is for the case where the derived class of B may or may not also derived from A.)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号