我的结构如下:
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的其他部分所需的某种RTTI。代码。
考虑到这一点,假设我已经知道dynamic_cast
,是否有一种通用的模式可以解决侧 -downcast问题而无需使用MyType
和RTTI类是从特定的trait
继承吗?我试图找到一个聪明的解决方案,因为它是代码的沉重瓶颈。
答案 0 :(得分:2)
在没有RTTI的情况下,您不能使用dynamic_cast
。除了一些特殊情况。
尽管您可以使用static_cast
或reinterpret_cast
(请不要使用),但是如果您弄错了,它就在 you 上-那么您将无法再测试nullptr
来查看投射是否成功
答案 1 :(得分:0)
首先,您必须使用static_cast
。 reinterpret_cast
确实不适合这样做。
但是为了使转换正常工作,您的程序需要知道它的运行方向。我的意思是说,它需要知道从A
到B
的转换路径。如果A
和B
在相同的类层次结构中,这很简单:只需按照所述的类层次结构进行转换。
但是如果您有:
struct C: A, B {};
这是A
和B
之间的唯一关系,static_cast
无法得知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
请注意,我是在通过首先向下转换为派生类型,然后“向上转换”回特征来准确地说明如何进行强制转换。
reinterpret_cast
如果要从类转换为基类(从MyType
到trait1
),dynamic_cast
将返回指向派生对象中基类子对象的指针或引用(static_cast
也可以正确进行此转换)。这意味着返回的指针的值实际上可能与提供的指针的值不同。 reinterpret_cast
永远不会对指针值进行此类更改。它只会将传递给它的任何内容重新解释为新类型,这显然是错误的。显而易见的结论是不要使用reinterpret_cast
在类层次结构内执行强制转换。