在修复庞大代码库中的错误时,我观察到一种奇怪的情况,引用的动态类型从原始Derived
类型更改为Base
类型!我提供了最少的代码来解释问题:
struct Base {
// some 'virtual' function
protected: // copy constructor
private: // assignment operator
};
struct Derived : Base {
... // There are few more classes between `Base` and `Derived`
... // but for simplicity, I have put direct relation
};
void foo (Base &ref)
{
SomeClass obj;
obj.pVoid = &ref; // pVoid is of void*
// ----> typeid(ref) = Derived
(*funcptr)(obj);
// ----> typeid(ref) = Base !!!
Derived *p = dynamic_cast<Derived*>(&ref); // this fails ... i.e. "p = 0"
}
funcptr
是一个函数指针 (void (*)(SomeClass&)
)。 funcptr
可以指向这么多函数,并且它们有自己的调用流程,因此调试起来很困难。
很奇怪的是,在调用函数指针之后,ref
的派生类型从Derived
变成了Base
。为了简化我的工作,我怀疑对象从 Derived
切片到 Base
,因此我将 ~Base()
设为纯 virtual
并重新编译整个源代码。但没有编译器错误,这意味着没有声明 Base
对象。
ref
Derived
的动态类型更改为 Base
以及 dynamic_cast
的潜在原因是什么> 后来失败了?
最佳答案
我不相信上面的代码与实际情况相同,因为代码示例无法编译!您不能隐式转换 Base*
由 dynamic_cast<Base*>(&ref)
产生至Derived*
.
也就是说,假设 typeid()
的输出实际上是正确的,对于引用更改的类型 ID 有一些可行的解释。所有这些都表明程序中存在某种形式的错误:
- 被调用的函数会销毁对象,例如通过调用道德上的等价物
dynamics_cast<Base*>(obj.pVoid)->~Base()
. - 被调用的函数在
obj.pVoid
指向的地址构造一个新对象。使用放置new
,即类似这样的:new(obj.pVoid) Base()
. - 某些内容正在覆盖内存,导致留下
Base
引用位置中的对象。 - 可能还有更多原因......
就我个人而言,我会赌第二种情况是情况,即一个对象被构造到该位置。显然,如果没有看到被调用的函数,就无法判断。
关于c++ - 在什么情况下,dynamic_cast<> 可能会失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9238711/