c ++ reinterpret_cast,virtual和templates好吗?

Seb*_*ski 2 c++ virtual templates casting reinterpret-cast

在C++中,假设以下类层次结构:

class BaseClass { };
class ChildClass : public BaseClass { };
Run Code Online (Sandbox Code Playgroud)

进一步假设这两个类的工厂类具有通用的模板化基类:

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
};
Run Code Online (Sandbox Code Playgroud)

需要注意的是的大小/内部结构ChildClassFactoryBaseClassFactory不同的是由于它们的不同的字段.

现在,如果有一个ChildClassFactory(或Factory<ChildClass>)的实例,我可以安全地将其转换为Factory<BaseClass>(通过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();
Run Code Online (Sandbox Code Playgroud)

我知道你不能总是以这种方式施放模板化的类,但在这种特殊情况下,演员应该是安全的,不应该吗?

我用Visual C++ 2010对它进行了测试,它确实有效.我现在的问题是这是否可以移植到其他编译器?

更新:由于存在一些混淆,让我在我的示例中澄清一些(应该是)重要的内容:

  • ChildClass 是一个儿童班 BaseClass
  • 用户Factory<BaseClass>不知道BaseClass将创建什么子类.他所知道的BaseClass只是创造了.
  • Factory<T> 没有自己的领域(除了vtable).
  • Factory::create()virtual

Pla*_*aHH 5

不它不是.reinterpret_cast除了一些特殊情况之外,您不得使用其他结果来反铸东西:

ISO14882:2011(e)5.2.10-7:

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

为了使可能的故障情况更加清晰,请考虑多重继承,其中使用static_castdynamic_cast有时会调整指针值,但reinterpret_cast不会.考虑从这个示例中转换A*B*:

struct A { int x; };
struct B { int y; };
struct C : A, B { };
Run Code Online (Sandbox Code Playgroud)

要了解代码如何以不同的方式失败,请考虑大多数编译器如何实现虚函数调用机制:使用虚拟指针.你的实例ChildClassFactory将有一个虚拟指针,指向虚拟表ChildClassFactory.现在当你成为reinterpret_cast这个野兽时,它恰好偶然"工作",因为编译器需要一些虚拟指针,指向一个具有相同/相似布局的虚拟表.但它仍将包含指向ChildCLassFactory虚函数的值,因此将调用这些函数.调用未定义的行为后,所有这些都很长.就好像你正在驾驶汽车进入一个大峡谷并且认为"嘿,一切都很好"只是因为你还没有到达地面.