C++ 无RTTI的动态_铸造

C++ 无RTTI的动态_铸造,c++,c++14,multiple-inheritance,rtti,dynamic-cast,C++,C++14,Multiple Inheritance,Rtti,Dynamic Cast,我的结构如下所示: 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 mana

我的结构如下所示:

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
trait1
类型之间没有直接关系,所以不起作用

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

考虑到这一点,假设我已经知道一个
MyType
类继承自一个特定的
trait
,那么是否有一种通用的模式可以在不使用
dynamic\u cast
和RTTI的情况下解决side downcast问题?我正试图找到一个聪明的解决方案,因为这是代码的一个严重瓶颈。

没有RTTI,您无法使用
动态\u cast
。除了几个角落的案子


您可以使用
static\u cast
reinterpret\u cast
(请不要这样做),但如果您弄错了,则由您自己承担-然后您就不能再测试
nullptr
以查看强制转换是否成功

第一件事:您必须使用
static\u cast
<代码>重新解释\u cast并不真正适用于此

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

但如果你有:

struct C: A, B {};
这是
A
B
之间的唯一关系,
static\u cast
无法了解
C
(这是RTTI提供的信息),因此它无法执行cast,因为
A
B
没有真正的关联

为了提供该路径,您必须使您的程序以某种方式知道它。最简单的方法是模板化
包装器

template<typename T>
class wrapper {
  managed_object* ptr;
public:
  template<typename Trait> Trait* object() const { 
    return static_cast<Trait*>(static_cast<T*>(ptr)); 
  }
};
模板
类包装器{
托管对象*ptr;
公众:
模板特征*对象()常量{
返回静态施法(静态施法(ptr));
}
};
然后:

mya型;
包装w{&a};
trait1*asTrait1=w.object();//好啊
请注意,我正在确切地告诉您如何进行转换,首先向下转换到派生类型,然后“向上转换”到trait

关于
重新解释cast

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

这就是重点,如果我的问题不清楚,我根本不想使用
dynamic\u cast
。我想找到一个不需要
dynamic\u cast
和RTTI的解决方案。实际上,只要不需要运行时查找,您就可以找到。也就是说,对基类进行强制转换或对同一类的限定版本进行强制转换是可以的。
static\u cast
不会将
managed\u对象
强制转换为
trait1
。这就是OP所说的“侧面向下问题”
reinterpret_cast
will,但随后修改对象是UB,因为这两种类型不相关。在基类中,您可以添加几十(数百?)个getter caster,如
virtual Foo*AsFoo(){return nullptr;}
,然后在Foo中放入
Foo*AsFoo()覆盖{return this;}
。你怎么知道这是一个严重的代码瓶颈?您是否在没有RTTI验证的情况下进行了评测?@marcinj:我无法在没有
dynamic\u cast
的情况下对其进行评测,因为我没有解决方案,但是是的,我评测了
dynamic\u cast
-ing花费了多少时间,所以我已经确定这是一个瓶颈。您是否考虑过将
wrapper
替换为
std::unique\u ptr
?这意味着您可以使用
std::unique_ptr
std::unique_ptr
在那些(理想情况下为数不多)精确派生类型起作用的地方使用完整的类型安全性,然后您可以始终将其转换为
std::unique_ptr
的泛型代码。看起来奇怪的是,重复模板模式(CRTP)是一种方法。
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