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

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 act from A * to B * I get the following error:

 cannot convert from base A to derived type B via virtual base A 
+44
c ++ casting virtual-inheritance static-cast downcasting
Sep 19 '10 at 19:04
source share
7 answers

To understand the casting system, you need to dive into the object model.

The classic representation of a simple hierarchical model is containment: if B comes from A , then the object B actually contains the subobject A along with its own attributes.

With this model, downcasting is a simple pointer manipulation with an offset known at compile time, which depends on the location of memory B

This is what static_cast does: the static actor is duplicated as static because the calculation of what is needed to create is performed at compile time, whether it be pointer or conversion arithmetic (*).

However, when virtual inheritance of strokes in things tends to get a little more complicated. The main problem is that with virtual inheritance, all subclasses have the same instance of a subobject. To do this, B will have a pointer to A instead of the correct A , and an object of the base class A will be created outside of B

Therefore, during compilation it is impossible to derive the necessary arithmetic of the pointer: it depends on the type of runtime of the object.

Whenever a runtime type dependency exists, you need RTTI (RunTime type information), and using RTTI for translations is the dynamic_cast job.

In short:

  • compile time: static_cast
  • dynamic_cast time: dynamic_cast

The other two are also compilations, but they are so specific that it is easy to remember why they are needed ... and they are smelly, so it’s better not to use them at all.

(*) As noted in the comments of @curiousguy in the comments, this is true only for downcasting. A static_cast allows you to level up, regardless of virtual or simple inheritance, although actuation is also not necessary.

+78
Sep 20 '10 at 7:02
source share

As far as I know, you need to use dynamic_cast because inheritance is virtual and you are fading away.

+11
Sep 19 '10 at 19:06
source share

You cannot use static_cast in this situation, because the compiler does not know the offset of B relative to A at compile time. The offset should be calculated at run time based on the exact type of the derived object itself. Therefore you should use dynamic_cast .

+6
Sep 19 '10 at 19:20
source share

Yes, you need to use dynamic_cast, but you have to make the base class A polymorphic, for example. adding virtual dtor.

+4
Sep 19 '10 at 19:28
source share

In accordance with standard documents

Section 5.2.9 - 9, for Static Cast ,

A value 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 derived class (section 10) from B if the valid standard conversion from "pointer to D "in" a pointer to B exists (4.10), cv2 is the same cv-qualification as a higher cv-qualification than cv1 and B is neither a virtual base class D nor a base class of a virtual base class D.

Therefore, this is not possible, and you should use dynamic_cast ...

+4
Sep 20 '10 at 6:01
source share

$ 5.2.9 / 2- "The expression e can be explicitly converted to type T using static_cast of the form static_cast (e) if the declaration is" T t (e) "; well-formed, for some I came up with a temporary variable t (8.5)."

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

Now "B * t (A *)" is not correctly formed in C ++ (but "A * t (B *)" is because "A" is a virtual unambiguous and accessible base "B." The code gives an error.

+1
Sep 20 '10 at 13:07
source share

I do not know if this is "safe", but.

Assuming

B derived from A (and pure virtual)

Since I KNOW that a pointer to B is still 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 returns the print "hello!". and the value of another object (in this case, "2").

By the way, what I'm doing is very unsafe (personally, I give a different identifier to each class and claim that after re-interpreting that the current identifier is equal to another identifier, we are sure that we are doing something with 2 equal classes), and, as you see, I limited myself to the "const" methods. Thus, this will work with "non-constant" methods, but if you do something wrong, then catching the error is almost impossible. And even with the statement, there is 1 chance of 4 billion to succeed, even when it must fail (assert (ID == other-> ID);)

By the way, a good OO design should not require this kind of thing, but in my case, I tried to reorganize / reverse engineer the code without refusing to use reinterpret casting. generally speaking, you CAN avoid this kind of thing.
+1
Nov 16 '12 at 14:45
source share



All Articles