多态虚拟基类?

当没有涉及虚拟功能时,是否有办法从虚拟基类向派生类下降? 下面是一些代码来演示我在说什么:

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);
}

请注意,该代码仅用于演示。 我的真实场景相当复杂,涉及到模板参数并从一个到另一个投射,只知道第一个是第二个的基础; 它可以是一个普通的或虚拟的基础,它可能有也可能没有虚拟功能。 (请参阅底部的简化示例)。 我可以使用类型特征检测多态案例和虚拟/非虚拟基础案例,并且解决除非多态虚拟基础之外的所有案例。 所以这就是我所问的。

我无法真正想到一种方法来演员:

  • 隐式转换是正确的; 这些只做upcasts。

  • 显式禁止static_cast从虚拟基类转换:

    5.2.9 / 2 ...和B既不是虚基类的D也不基类的虚拟基类中的D 。 ...

  • dynamic_cast也无法做到,因为向下转换需要一个多态类

    5.2.7 / 6否则, v应该是多态类型的指针或glvalue(10.3)。

    10.3 / 1 ...声明或继承虚函数的类称为多态类。

  • reinterpret_cast在这里根本不适用。

  • 如果MostDerived至少有一个虚函数,那么当然可以用dynamic_cast解决。 但是,如果没有,是否有办法演员演员?

    (注意所有的引号都来自C ++ 11草案N3485)


    鉴于以上关于上述示例代码的评论过多,下面是我真实情况的草图:

    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);
      }
    };
    

    也就是说,我知道T_Base是一个基类的T_MostDerived (我知道T_MostDerived是真正最派生类型),但我不知道什么对他们; Bar是我的代码,是未知客户可以使用的图书馆的一部分。 我可以检测到它是一个非多态虚拟基础,但在这种情况下我不能投射它。


    MostDerived& ViBase&隐含着明显的转换。 static_cast可以明确表达这样的转换,也可以做相反的转换。 这就是static_cast所做的各种转换。

    正如OP所指出的,从虚拟基地down掉static_cast是无效的。

    下面的源代码说明了原因:

    #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 );
    }
    

    本质上,正如所示,你不能从D (或E )的声明中推断出地址的调整。 编译器也不是。 这也排除了reinterpret_cast


    这需要一个黑客。 downcast需要数学,因为多重继承可能会将基类置于派生类中的任意位置。 但是,如果您知道基类实际上是继承的,那么在派生类中应该只有它的一个实例。 这意味着你可以创建一个转换函数:

    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);
      }
    };
    

    什么特殊的C ++转换给你这个函数不是类型安全的。 这个函数一味地假设传入的ViBase有一个合适的派生子进行投射,通常情况并非如此。

    链接地址: http://www.djcxy.com/p/78945.html

    上一篇: polymorphic virtual base class?

    下一篇: Access to protected constructor of base class