Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ - downcasting a diamond shape inherited object without RTTI/dynamic_cast

I'm currently working on integrating a third-party package that uses lots of RTTI stuff on a non-RTTI platform (Android). Basically, I did my own RTTI implementation but I'm stuck on a problem.

The issue is that a lot of classes are having the diamond inheritance problem since all the classes derive from the same base class (object).. and so, if I want to downcast from the base class to the derived class, I have to use a dynamic_cast - but RTTI is not available! How do I convert an object from parent to child when there are virtual inheritance without dynamic_cast?

It looks like that:

class A 
{
public:
 virtual char* func() { return "A"; };
};
class B : public virtual A
{
public:
 //virtual char* func() { return "B"; };
};
class C : public virtual A 
{
public:
 //virtual char* func() { return "C"; };
};

class D : public B, public C 
{
public:
 //virtual char* func() { return "D"; };
};

D d;
A* pa = static_cast<A*>(&d);
D* pd = static_cast<D*>(pa); // can't do that! dynamic_cast does work though...

Those are my errors:

error C2635: cannot convert a 'A*' to a 'D*'; conversion from a virtual base class is implied

error C2440: 'initializing' : cannot convert from 'test_convert::A *' to 'test_convert::D *' Cast from base to derived requires dynamic_cast or static_cast

Any ideas?

like image 790
Adam Avatar asked Jul 27 '10 20:07

Adam


People also ask

Does dynamic_cast require RTTI?

The fact, that the cast is safe is known by the compiler at compile time. This means, that dynamic_cast does not need to use RTTI. We can say in general, that dynamic_cast is a tool for moving around the inheritance tree – up and down.

How can we solve diamond problem in inheritance?

The Diamond Problem is fixed using virtual inheritance, in which the virtual keyword is used when parent classes inherit from a shared grandparent class. By doing so, only one copy of the grandparent class is made, and the object construction of the grandparent class is done by the child class.

How do I resolve a diamond problem in CPP?

Solution of the Diamond Problem: The solution is to use of the keyword virtual on the two parent classes ClassA and ClassB. Two-parent classes with a common base class will now inherit the base class virtually and avoid the occurrence of copies of the base class in the child class (ClassC here).

Is Diamond inheritance results in compiler error?

The answer to the titular question is no.


2 Answers

You can only do this cast with dynamic_cast; no other cast will do this.

If you can't design your interfaces so that you don't need to perform this type of cast then the only thing you can do is make the casting functionality part of your class hierarchy.

E.g. (horribly hacky)

class D;

class A
{
public:
    virtual D* GetDPtr() { return 0; }
};

class B : public virtual A
{
};

class C : public virtual A 
{
};

class D : public B, public C 
{
public:
    virtual D* GetDPtr() { return this; }
};
like image 163
CB Bailey Avatar answered Oct 17 '22 08:10

CB Bailey


Android does support RTTI. You need latest NDK (at least r5, latest is r6) and you need to compile against the GNU stdlibc++ instead of the default.

Even before, there was the CrystaX's rebuild which did support exceptions and rtti (we had to use that until official NDK r5c because r5a and r5b had the support, but crashed on older (pre-2.3) systems).

PS: Somebody should really forbid vendors say they support C++ when they don't support exceptions and rtti, because most of standard library, and that's part of the C++ standard, does not work without either. Plus not supporting them is silly, especially for the exceptions, because code with exceptions is more efficient than one without (provided they are properly used to signal exceptional cases).

like image 40
Jan Hudec Avatar answered Oct 17 '22 08:10

Jan Hudec