代码之家  ›  专栏  ›  技术社区  ›  Jack

不带RTTI的动态_铸造

  •  2
  • Jack  · 技术社区  · 7 年前

    我的结构如下:

    struct managed_object {
      virtual ~managed_object() { }
    };
    
    class trait1 {
      public: 
        virtual void myMethod() const = 0;
    };
    
    class trait2 {
      public: 
        virtual void myOtherMethod(int x) const = 0;
    };
    
    class MyType final : public managed_object, public trait1 {
     ...
    };
    
    class MyType2 final : public managed_object, public trait1, public trait2 {
     ...
    };
    
    class wrapper {
      private:
        managed_object* ptr;
      public:
        template<typename T> T* object() const { 
          return dynamic_cast<T*>(data.ptr); 
        }
    };
    

    所以基本上我有一个 managed_object 多个类型从中继承的基类。每个亚型都可以从任何特征组合中继承,它们是 final 所以我相信他们在继承方面不会有更深层次的了解。

    这段代码之所以能够正常工作,是因为RTTI承担了将所有东西粘合在一起的任务,但代价很高

    wrapper w = ...
    trait* asTrait1 = w.object<trait1>;
    

    因为两者之间没有直接关系,所以不起作用 托管对象 trait1 类型。

    在我的完整代码中,我已经确定 dynamic_cast 不会失败,因为我有额外的数据(示例中未显示),它为我提供了代码其他部分所需的某种RTTI。

    考虑到这一点,有没有共同的模式来解决这个问题 一边 -不需要使用 动态投影 RTTI假设我已经知道 MyType 类是从特定的 trait ? 我正试图找到一个聪明的解决方案,因为这是代码的一个严重瓶颈。

    2 回复  |  直到 7 年前
        1
  •  5
  •   Jesper Juhl    7 年前

    不能 使用 dynamic_cast 没有RTTI。除了几个角落的案子。

    可以 使用 static_cast reinterpret_cast (请不要)尽管如此,但它是开着的 如果你弄错了,那么你就不能再进行测试了 nullptr 看看演员阵容是否成功

        2
  •  1
  •   Not a real meerkat    6 年前

    第一件事:你必须使用 static_cast . reinterpret_cast 不太适合这个。

    但是为了让演员们发挥作用,你的节目需要知道它要去哪里。我的意思是,它需要知道它必须走的路 A B 如果 A. B 都在同一个类层次结构上,这很简单:只需按照所述的类层次结构执行演员阵容。

    但如果你有:

    struct C: A, B {};
    

    这是他们之间唯一的联系 A. B , 静态投影 无法得知 C (这是RTTI提供的信息),因此它无法执行演员阵容,因为 A. B 其实没有什么关系。

    为了提供这条路径,你必须让你的程序以某种方式知道它。最简单的方法是模板化 wrapper :

    template<typename T>
    class wrapper {
      managed_object* ptr;
    public:
      template<typename Trait> Trait* object() const { 
        return static_cast<Trait*>(static_cast<T*>(ptr)); 
      }
    };
    

    然后:

    MyType a;
    wrapper<MyType> w{&a};
    trait1* asTrait1 = w.object<trait1>(); // OK
    

    请注意,我正在确切地告诉您如何进行转换,首先向下转换到派生类型,然后“向上转换”到trait。

    关于 重新解释

    如果从基类转换为基类( MyType trait1 ), dynamic_cast 会回来的 指向派生对象中基类子对象的指针或引用 ( 静态投影 也可以正确地进行这种转换)。这意味着返回指针的值实际上可能与提供的指针的值不同。 重新解释 永远不会对指针值进行这样的更改。它只会将传递给它的任何东西重新解释为新类型,这显然是错误的。显而易见的结论是不要使用 重新解释 在类层次结构中执行强制转换。