[英]dynamic_cast without RTTI
我的结构如下:
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>;
将不起作用,因为managed_object
和trait1
类型之间没有直接关系。
在我完整的代码中,我已经确定所有dynamic_cast
都不会失败,因为我还有其他数据(示例中未显示),这为我提供了其他代码部分所需的RTTI。
鉴于此,假设我已经知道MyType
类是从特定trait
继承来的,是否有一种无需使用dynamic_cast
和RTTI即可解决旁投问题的通用模式? 我试图找到一个聪明的解决方案,因为它是代码的沉重瓶颈。
没有RTTI, 就不能使用dynamic_cast
。 除了一些极端情况。
您可以使用static_cast
或reinterpret_cast
(请不要使用),但是如果您弄错了,它就在您身上-然后您将无法再测试nullptr
以查看转换是否成功
首先,您必须使用static_cast
。 reinterpret_cast
并不是很适合此操作。
但是,为了使转换正常工作,您的程序需要知道运行的方向。 我的意思是,它需要知道从A
投射到B
必须采取的路径。 如果A
和B
在相同的类层次结构中,这很简单:只需按照所述的类层次结构进行转换。
但是,如果您有:
struct C: A, B {};
并且这是A
和B
之间的唯一关系, static_cast
无法了解C
(这是RTTI提供的信息的一种),因此由于A
和B
并不真正相关,因此它无法执行static_cast
。
为了提供该路径,您必须使您的程序以某种方式知道它。 最简单的方法是模板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
请注意,我是在通过首先向下转换为派生类型,然后“向上转换”回特征来准确地说明如何进行转换。
reinterpret_cast
如果要从类转换为基类(从MyType
为trait1
),则dynamic_cast
将返回派生对象中基类子对象的指针或引用 ( static_cast
也可以正确进行此转换)。 这意味着返回的指针的值实际上可能与提供的指针的值不同。 reinterpret_cast
将永远不会对指针值进行此类更改。 它只会将传递给它的任何内容重新解释为新类型,这显然是错误的。 显而易见的结论是不要在类层次结构内使用reinterpret_cast
进行强制类型转换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.