我有一个控制器函数来处理许多对象,这些对象的特定类都是从纯虚拟类派生的。
class Abstract {
public:
virtual bool ReadyForWork() = 0;
virtual void DoWork() = 0;
};
然后我有以下内容:
class Specific : public virtual Abstract {
public:
bool ReadyForWork();
void DoWork();
};
程序创建一个Specific实例,并将其分配给一个链中的void指针。
vChain->Append(new Specific());
到目前为止,这么好。当控制器功能启动并尝试访问Specific的Abstract的虚函数实现时,虽然... eww。
特定对象在那里,我可以通过将vChain的内部void *转换为Specific *来访问其内容,并且它都会检出,因此不良内存不是问题。但是当我将void *转换为Abstract *时,编译器会丢失对Specific的实现的引用,将函数地址更改为与之前完全不同的函数 - 即使指向对象本身的指针是正确的。试图
// ...
Abstract *vWorkObj = (Abstract*)vChain->GetObj();
if (vWorkObj->ReadyForWork()) {
// ...
在我脸上产生以下结果:
Unhandled exception at 0x00000054 in Proj.exe:
0xC0000005: Access violation executing location 0x00000054.
但如果我这样做
// ...
Abstract *vWorkObj = (Specific*)vChain->GetObj();
if (vWorkObj->ReadyForWork()) {
// ...
它没有打嗝就跑了。不幸的是,这对我没什么帮助,因为将会有多个继承自Abstract的类。
我在概念验证项目中尝试了类似的东西并且运行顺利:
// ...
bool ReadyForWork(Abstract *pObjPtr) {
// ...
// ...
Specific *vObj = new Specific();
if (ReadyForWork(vObj)) {
// ...
显然,编译器不喜欢在运行时解析继承类。 是否有办法访问抽象类的继承者而不明确告诉编译器它是哪个继承者?
我怀疑来自void *的转换可能是导致编译器失去方向的原因,但是如果链可以保持尽可能通用的话会省去一些麻烦。
我正在使用VS2013 Express for Windows Desktop。谢谢你的时间。
答案 0 :(得分:1)
问题的直接来源可能是您正在使用虚拟继承,这会使您的类的布局复杂化。它通常只在复杂的多继承场景中需要,所以也许你不需要它。
您想要一个指向Abstract
的{{1}}子对象的指针,它可能与您的情况下的内存地址不同。因此,如果您将Specific
存储在Abstract*
中,请务必首先转换为vChain
来存储正确的地址:
Abstract*
除此之外,首先有vChain->Append(static_cast<Abstract*>(new Specific()));
包含vChain
的问题。如果它将存储void*
,则根本不需要显式的强制转换,编译器会自动找出正确的指针。
答案 1 :(得分:1)
通常,当您将foo*
转换为void*
时,只有 才能安全转换回完全相同的类型。有些情况下它可以工作,有些情况下它可以正常工作,但基本上在每种情况下你最好遵循这条规则。
如果您打算稍后将void*
转换为abstract*
,请先将foo*
转换为abstract*
,然后再将其转换为{ {1}}。最好的这种转换是隐含的。
void*
最后,如果您知道稍后要转换为abstract* p = new foo;
void* v = static_cast<void*>(p);
abstract*p2 = static_cast<abstract*>(v);
,请考虑将同时存储的指针类型更改为abstract*
。