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