c++relpret_cast、virtual和templates都可以
c++ reinterpret_cast, virtual, and templates ok?
在C++中,假设以下类层次结构:
class BaseClass { };
class ChildClass : public BaseClass { };
进一步假设这两个类的工厂类具有一个通用的模板基类:
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
的大小/内部结构由于它们的字段不同而不同。
现在,如果有一个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();
我知道不能总是以这种方式强制转换模板类,但在这种特殊情况下,强制转换应该是安全的,不是吗?
我已经用Visual C++2010对它进行了测试,它确实有效。我现在的问题是,这是否可以移植到其他编译器?
更新:由于出现了一些混乱,让我进一步澄清一下在我的示例中什么(应该)是重要的:
ChildClass
是BaseClass
的一个子类Factory<BaseClass>
的用户不知道将创建BaseClass
的哪个子类。他只知道BaseClass
是被创造出来的Factory<T>
没有自己的字段(除了vtable)Factory::create()
为virtual
不,不是。除了抛出内容之外,您可能不会使用reinterpret_cast
的结果,除非有一些特殊情况:
ISO14882:2011(e)5.2.10-7:
对象指针可以显式转换为不同的类型。70当类型为"pointer to T1"的prvalue v为转换为类型"指向cv T2的指针",如果T1和T2都是标准布局,则结果为static_cast类型(3.9),T2的对准要求不严格于T1的那些,或者如果任一类型是空的。转换类型的prvalue"指针到T1"到类型"指针到T2"(其中T1和T2是对象类型,其中T2的对齐要求为否比T1的那些更严格)并且回到其原始类型产生原始指针值。任何其他此类指针的结果转换未指定。
为了使可能的失败场景更加清楚,可以考虑多重继承,其中使用static_cast
或dynamic_cast
有时会调整指针值,但reinterpret_cast
不会。考虑在本例中从A*
转换为B*
:
struct A { int x; };
struct B { int y; };
struct C : A, B { };
要了解代码是如何以不同的方式失败的,请考虑大多数编译器是如何实现虚拟函数调用机制的:使用虚拟指针。ChildClassFactory
的实例将有一个虚拟指针,指向ChildClassFactory
的虚拟表。现在,当你reinterpret_cast
这个野兽时,它只是碰巧"工作"了,因为编译器需要一些虚拟指针,指向一个布局相同/相似的虚拟表。但它仍将包含指向ChildCLassFactory
虚拟函数的值,因此这些函数将被调用。在调用未定义的行为之后,所有这些都很长。就好像你开车跳进一个大峡谷,只因为你还没有落地就想"嘿,一切都很好"。
否,interpret_cast仅用于低级代码,因为它不会执行正确的地址操作。请改用static_cast或dynamic_cast,
你为什么想要两个工厂?这不符合GoF工厂的模式。
interpret_cast不是这样做的方法,因为它很慢(运行时检查),并且不是一个很好的OO设计(您希望在语言中使用polymophism构建)。
相反,在生成所追求的类型的工厂类中生成构造函数,然后让这些构造函数调用各个类型的构造函数。
工厂模式允许您对实现中的更改一无所知,这是一件好事,因为您可以最大限度地减少依赖关系,并允许在未来更容易地维护代码。
我勾选了上面的原始答案(为了表扬他),但我想我应该总结一下我在这里学到的东西。
因此,基本问题是没有定义必须如何实现调度虚拟呼叫。
这意味着,内部用于虚拟呼叫调度的数据结构(例如vtables)在从同一模板创建的模板实例化之间可能是位兼容的,也可能是不兼容的。
- C++映射有2个键,这样任何1个键都可以用来获取值
- 任何人都可以告诉我我的 C++ 代码出了什么问题?
- 任何人都可以弄清楚这段代码如何显示运行错误?它打印无限时间 -1 以及正确答案
- 任何人都可以解释一下我是否需要 & 在第一个代码片段中
- 任何人都可以查明我的递归函数中的错误吗?
- Qt C++创建一个所有类都可以访问的全局变量
- 任何方法都可以在C++中比较数据结构中的许多方法
- 交叉和计算,任何人都可以解释代码吗?
- 我的合并排序没有给出正确的排序数组,任何人都可以解释一下吗?
- 任何人都可以解释这个初始值设定项代码吗?
- 如何使用C++共享目录,以便每个人都可以访问
- 任何人都可以在带有JNI的Android Studio上帮助我解决此错误,是否缺少一些内容?
- 如何制作一个结构程序,在其中可以存储无限量的数据,以便每次您想要时都可以将另一个产品添加到列表中?
- 任何人都可以检查这个回文 c++ 代码是否正确
- 任何机构都可以在运算符重载中解释这行代码
- 任何人都可以为我解释这个C
- C :对输入验证函数进行编程的性能影响可以对其进行编程,而每次都可以将其编程
- 任何人都可以解释此程序的类型促销以及为什么输出相同
- STXXL的任何STXXL替代方案都可以在编译时处理未知大小或任何技巧
- c++relpret_cast、virtual和templates都可以