c ++ reinterpret_cast,virtual和templates ok? [英] c++ reinterpret_cast, virtual, and templates ok?

查看:165
本文介绍了c ++ reinterpret_cast,virtual和templates ok?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在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 of BaseClass
  • A user of Factory<BaseClass> doesn't know what child class of BaseClass will be created. All he knows is that BaseClass is created.
  • Factory<T> has no fields of its own (other than the vtable).
  • Factory::create() is virtual

推荐答案

除了少数特殊情况之外,您不能使用 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:


对象指针可以显式转换为
a不同类型.70当类型指针到T1的prvalue v是
转换为类型指向cv T2的指针时,如果T1和T2都是标准的,则结果是static_cast(static_cast(v)布局
类型(3.9)和T2的对齐要求不比T1的
更严格,或者如果任一类型为void。将
类型的指针转​​换为类型指向T2的类型(其中T1和T2是
对象类型,其中T2的对齐要求不是
)的T1)并返回其原始类型,产生
原始指针值。任何其他此类指针
转换的结果未指定。

An object pointer can be explicitly converted to an object pointer of a different type.70 When a prvalue v of type "pointer to T1" is converted to the type "pointer to cv T2", the result is static_cast(static_cast(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1, or if either type is void. Converting a prvalue of type "pointer to T1" to the type "pointer to T2" (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.

为了使可能的故障情况更清楚, ,其中使用 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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆