我教一个C ++编程类,我已经看到了足够多的错误类型,我对如何诊断常见的C ++错误有很好的感觉。但是,有一种主要类型的错误,我的直觉并不是特别好:什么编程错误会导致对纯虚函数的调用?我见过的最常见错误导致调用虚拟函数来自基类构造函数或析构函数的函数。在帮助调试学生代码时,还有其他我应该注意的事项吗?
答案 0 :(得分:28)
“我见过的最常见错误导致这是从基类构造函数或析构函数调用虚函数。”
构造对象时,指向虚拟调度表的指针最初瞄准最高超类,并且它仅在中间类完成构造时更新。因此,您可能会意外地调用纯虚拟实现,直到子类(具有自己的重写函数实现)完成构造。这可能是派生程度最高的子类,也可能介于两者之间。
如果您按照指向部分构造的对象的指针(例如,由于异步或线程操作而处于竞争状态),可能会发生这种情况。
如果编译器有理由认为它知道指针到基类指向的实际类型,则它可以合理地绕过虚拟调度。你可能会通过做一些未定义的行为(例如重新解释演员)来混淆它。
在销毁期间,虚拟调度表应该在派生类被销毁时恢复,因此可以再次调用纯虚拟实现。
破坏后,通过“悬空”指针或引用继续使用对象可以调用纯虚函数,但在这种情况下没有定义的行为。
答案 1 :(得分:8)
以下是一些可能发生纯虚拟呼叫的情况。
static_cast
错误类型(或C样式转换)的答案 2 :(得分:0)
例如,当对象的引用或指针指向NULL位置,并且您使用对象引用或指针调用类中的虚函数时,可能会发生这种情况。例如:
std::vector <DerivedClass> objContainer;
if (!objContainer.empty())
const BaseClass& objRef = objContainer.front();
// Do some processing using objRef and then you erase the first
// element of objContainer
objContainer.erase(objContainer.begin());
const std::string& name = objRef.name();
// -> (name() is a pure virtual function in base class,
// which has been implemented in DerivedClass).
此时存储在objContainer [0]中的对象不存在。索引虚拟表时,找不到有效的内存位置。因此,发出运行时错误,称“称为纯虚函数”。