How to downplay from a non-polymorphic virtual base class?

Is there a way to dump a virtual base class into a derived class if there are no virtual functions? Here is some code to demonstrate what I'm talking about:

struct Base1 { int data; }; struct Base2 { char odd_size[9]; }; struct ViBase { double value; }; struct MostDerived : Base1, Base2, virtual ViBase { bool ok; }; void foo(ViBase &v) { MostDerived &md = somehow_cast<MostDerived&>(v); //but HOW? md.ok = true; } int main() { MostDerived md; foo(md); } 

Please note that the code is for demonstration purposes only. My real scenario is quite complicated and includes template parameters and casting from one to another, knowing only that the first of them is the base of the second; it may be a normal or virtual database, and it may or may not have virtual functions. (See a simplified example below). I can detect the polymorphic case and the virtual / non-virtual base case using type attributes and solve all of them except the non-polymorphic virtual base. So what I ask.

I really can't think of a way to make the cast:

  • Implicit conversions immediately; they only do upcasts.

  • static_cast explicitly prohibited for casting from a virtual base class:

    5.2.9 / 2 ... and B is neither a virtual base class of D , nor a base class of a virtual base class D ....

  • dynamic_cast cannot do this either, since downcasts require a polymorphic class

    5.2.7 / 6 Otherwise, v must be a pointer or a gl value of the polymorphic type (10.3).

    10.3 / 1 ... A class that declares or inherits a virtual function is called a polymorphic class.

  • reinterpret_cast does not apply here at all.

If MostDerived had at least one virtual function, this, of course, could be solved using dynamic_cast . But when this does not happen, is there a way to make a throw?

(NOTE: All quotes are taken from the C ++ 11 N3485 project)


In the light of the comments, there is too much special attention in the above code example, here is a sketch of my real situation:

 template <class T_MostDerived> struct Bar { template <class T_Base> void foo(T_Base &b, typename std::enable_if<std::is_base_of<T_Base, T_MostDerived>::value>::type * = nullptr) { T_MostDerived &md = somehow_cast<T_MostDerived>(b); do_stuff_with(md); } }; 

That is, I know that T_Base is the base class of T_MostDerived (and I know that T_MostDerived is really the most derived type), but I don't know anything about them; Bar is my code, part of a library that unknown clients can use. I may find that this is not a polymorphic virtual database, but I cannot distinguish it in this case.

+5
c ++ virtual-inheritance downcasting
source share
2 answers

There is an implicit unambiguous conversion from MostDerived& to its ViBase& . A static_cast can explicitly express such a transformation and can also do the inverse transformation. These are the types of conversions that static_cast does.

Because the OP noted that static_cast down from the virtual base is not valid.

The source code below shows why:

 #include <iostream> using namespace std; struct B { virtual ~B(){} }; struct D: virtual B {}; struct E: virtual B {}; struct X: D, E {}; auto main() -> int { X x; B& b = static_cast<E&>( x ); // Can't do the following for the address adjustment that would work for // D sub-object won't work for E sub-object, yet declarations of D and E // are identical -- so the address adjustment can't be inferred from that. // //static_cast<D&>( b ); // This is OK: dynamic_cast<D&>( b ); } 

Essentially, as shown in the figure, you cannot deduce the address setting from declaration D (or E ) alone. And the compiler cannot. This also excludes reinterpret_cast .

+4
source share

This requires hacking. The disadvantage requires mathematics, since multiple inheritance can put a base class in an arbitrary position within a derived class. However, if you know that the base class is actually inherited, then in the derived class there should be only one instance. This means that you can create a conversion function:

 struct MostDerived : Base1, Base2, virtual ViBase { bool ok; template <typename T> static MostDerived * somehow_cast (T *v) { static MostDerived derived; static T &from = derived; static size_t delta = reinterpret_cast<char *>(&from) - reinterpret_cast<char *>(&derived); char *to = reinterpret_cast<char *>(v); return reinterpret_cast<MostDerived *>(to - delta); } }; 

What special C ++ casts give you that this function is not type safety. This function blindly assumes that the one passed to ViBase has a suitable derived child for inclusion, which is usually not the case.

+2
source share

All Articles