问题描述
在C ++中,假设以下类层次结构:
In C++, assume following class hierarchy:
class BaseClass { };
class ChildClass : public BaseClass { };
b
$ b
Further assume factory classes for these two classes with a common, templated base class:
template<typename T>
class Factory {
public:
virtual T* create() = 0;
};
class BaseClassFactory : public Factory<BaseClass> {
public:
virtual BaseClass* create() {
return new BaseClass(&m_field);
}
private:
SomeClass m_field;
};
class ChildClassFactory : public Factory<ChildClass> {
public:
virtual ChildClass* create() {
return new ChildClass(&m_field);
}
private:
SomeOtherClass m_field; // Different class than SomeClass
};
注意 ChildClassFactory
和 BaseClassFactory
由于它们不同的字段而不同。
Note that the size/internal structure of ChildClassFactory
and BaseClassFactory
is different due to their different fields.
现在,如果a有一个 ChildClassFactory
(或 Factory< ChildClass>
),我可以安全地将其转换为 Factory< BaseClass> code>(通过
reinterpret_cast
)?
Now, if a have an instance of ChildClassFactory
(or Factory<ChildClass>
), can I safely cast it to Factory<BaseClass>
(via reinterpret_cast
)?
Factory<ChildClass>* childFactory = new ChildClassFactory();
// static_cast doesn't work - need to use reinterpret_cast
Factory<BaseClass>* baseFactory = reinterpret_cast<Factory<BaseClass>*>(childFactory);
// Does this work correctly? (i.e. is "cls" of type "ChildClass"?)
BaseClass* cls = baseFactory->create();
我知道你不能总是以这种方式转换模板类,但在这种特殊情况下,应该安全,不应该吗?
I know that you can't always cast templated classes this way, but in this special case a cast should be safe, shouldn't it?
我用Visual C ++ 2010测试了它,它工作。
I've tested it with Visual C++ 2010 and it does work. My question now is whether this is portable to other compilers?
在我的例子中很重要:
-
ChildClass
code> BaseClass -
Factory< BaseClass>
的用户不知道将创建BaseClass
类。所有他知道的是创建BaseClass
。 -
Factory< T>
没有自己的字段(除了vtable)。 -
Factory :: create()
虚拟
ChildClass
is a child class ofBaseClass
- A user of
Factory<BaseClass>
doesn't know what child class ofBaseClass
will be created. All he knows is thatBaseClass
is created. Factory<T>
has no fields of its own (other than the vtable).Factory::create()
isvirtual
推荐答案
除了少数特殊情况之外,您不能使用 reinterpret_cast
的结果来投放内容:
No, it is not. You may not use the result of a reinterpret_cast
other than to cast stuff back, except for a few special cases:
ISO14882:2011(e)5.2.10-7:
ISO14882:2011(e) 5.2.10-7:
为了使可能的故障情况更清楚, ,其中使用 static_cast
或 dynamic_cast
有时会调整指针值,但 reinterpret_cast
不会。考虑在此示例中从
A *
转换为 B *
:
To make a possible failure scenario more clear, consider multiple inheritance, where using a static_cast
or dynamic_cast
would sometimes adjust the pointer value, but reinterpret_cast
will not. Consider casting in this example from A*
to B*
:
struct A { int x; };
struct B { int y; };
struct C : A, B { };
要理解代码以不同的方式失败,请考虑大多数编译器如何实现虚函数调用机制:具有虚指针。您的 ChildClassFactory
实例将有一个虚指针,指向 ChildClassFactory
的虚表。现在当你 reinterpret_cast
这个野兽,它偶然发生工作偶然,因为编译器期望一些虚拟指针,指向一个虚拟表将具有相同/相似的布局。但它仍然包含指向 ChildCLassFactory
虚函数的值,因此将调用这些函数。所有这些都是在调用未定义的行为之后长的 。这就好像你正在用一辆汽车跳进一个大峡谷,并认为嘿,一切都驾驶很好,因为你还没有击中地面。
To understand how your code fails in a different way too, consider how most compilers implement the virtual function call mechanism: With virtual pointers. Your instance of ChildClassFactory
will have a virtual pointer, pointing to the virtual table of ChildClassFactory
. Now when you reinterpret_cast
this beast, it just happens to "work" incidentally, because the compiler expects some virtual pointer, pointing to a virtual table that will have the same/similar layout. But it will still contain the values pointing to the ChildCLassFactory
virtual functions, thus these functions would be called. All of this is long after invoking undefined behaviour. It is as if you are jumping with a car into a large canyon and thinking "hey, everything is driving fine" just because you have not hit the ground yet.
这篇关于c ++ reinterpret_cast,virtual和templates ok?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!