C++ cannot convert from base A to derived type B via virtual base A

C++CastingDowncastVirtual InheritanceStatic Cast

C++ Problem Overview


I have three classes:

class A {};

class B : virtual public A {};
class C : virtual public A {};

class D: public B, public C {};

Attempting a static cast from A* to B* I get the below error:

cannot convert from base A to derived type B via virtual base A

C++ Solutions


Solution 1 - C++

In order to understand the cast system, you need to dive into the object model.

The classic representation of a simple hierarchy model is containment: if B derives from A then the B object will, in fact, contain an A subobject alongside its own attributes.

With this model downcasting is a simple pointer manipulation by an offset known at compilation time, which depends on the memory layout of B.

This is what static_cast does: a static cast is dubbed static because the computation of what is necessary for the cast is done at compile-time, be it pointer arithmetic or conversions (*).

However, when virtual inheritance kicks in, things tend to become a bit more difficult. The main issue is that with virtual inheritance all subclasses share the same instance of the subobject. In order to do that, B will have a pointer to an A, instead of an A proper, and the A base class object will be instantiated outside of B.

Therefore, it's impossible at compilation time to be able to deduce the necessary pointer arithmetic: it depends on the runtime type of the object.

Whenever there is a runtime type dependency, you need RTTI (RunTime Type Information), and making use of RTTI for casts is the job of dynamic_cast.

In summary:

  • compile-time downcast: static_cast
  • run-time downcast: dynamic_cast

The other two are also compile-time casts, but they are so specific that it's easy to remember what they are for... and they are smelly, so better not use them at all anyway.

(*) As noted by @curiousguy in the comments, this only holds for downcasting. A static_cast allows upcasting regardless of virtual or simple inheritance, though then the cast is also unnecessary.

Solution 2 - C++

As far as I know, you need to use dynamic_cast because the inheritance is virtual and you're downcasting.

Solution 3 - C++

You can't use static_cast in this situation because the compiler doesn't know the offset of B relative to A at compile time. The offset must be calculated at run-time based on the exact type of the most derived object. Therefore you must use dynamic_cast.

Solution 4 - C++

Yes, you have to use a dynamic_cast, but you'll have to make the base class A polymorphic, e.g. by adding a virtual dtor.

Solution 5 - C++

According standard docs,

Section 5.2.9 - 9, for Static Cast,

>An rvalue of type “pointer to cv1 B,” where B is a class type, can be converted to an rvalue of type “pointer to cv2 D,” where D is a class derived (clause 10) from B, if a valid standard conversion from “pointer to D” to “pointer to B” exists (4.10), cv2 is the same cv-qualification as, or greater cv-qualification than, cv1, and B is neither a virtual base class of D nor a base class of a virtual base class of D.

Hence, it is not possible and you should use dynamic_cast...

Solution 6 - C++

> $5.2.9/2- "An expression e can be > explicitly converted to a type T using > a static_cast of the form > static_cast(e) if the declaration > “T t(e);” is well-formed, for some > invented temporary variable t (8.5)."

In your code you are attempting static_cast with 'T = B*' and 'e = A*'

Now 'B* t(A*)' is not well-formed in C++ (but 'A* t(B*)' is because 'A' is a virtual unambiguous and accessible base of 'B'. Therefore the code gives error.

Solution 7 - C++

I don't know if this is "safe" but.

Assuming

B derived from A (and A pure virtual)

Since I KNOW that a pointer to B still remains a pointer to B.

    class A
    {
            virtual void doSomething(const void* p) const =0;
    };

    class B
    {
    public:
            int value;
            virtual void doSomething(const void*p)const
            {
            const B * other = reinterpret_cast<const B*>(p);
            cout<<"hello!"<< other->value <<endl;
            }
    };

    int main()
    {
            B  foo(1),bar(2);
            A * p = &foo, q=&bar;
            p->doSomething(q);
            return 0;
    }

this program executes and correctly return printing "hello!" and the value of the other object (in this case "2").

by the way, what I'm doing is highly unsafe (personally I give a different ID to every class and I assert after reinterpret casting that current ID is equal to other ID to be sure we are doing something with 2 equal classes) and as you see I limited myself to "const" methods. Thus this will work with "non-const" methods, but if you do something wrong catching the bug will be almost unpossible. And even with assertion there's a 1 chance out of 4 billions to succeed assertion even when it is supposed to fail (assert(ID== other->ID);)

By the way.. A good OO design should not require this kinda of stuff, but in my case I tried to refactor/re-design the code without being able to drop the usage of reinterpret casting. generally speaking you CAN avoid this kind of things.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPanayiotis KarabassisView Question on Stackoverflow
Solution 1 - C++Matthieu M.View Answer on Stackoverflow
Solution 2 - C++Jon PurdyView Answer on Stackoverflow
Solution 3 - C++Yakov GalkaView Answer on Stackoverflow
Solution 4 - C++NicoView Answer on Stackoverflow
Solution 5 - C++liaKView Answer on Stackoverflow
Solution 6 - C++ChubsdadView Answer on Stackoverflow
Solution 7 - C++CoffeDeveloperView Answer on Stackoverflow