我教了一门 C++ 编程课程,我已经看到了足够多的错误类别,我对如何诊断常见的 C++ 错误有很好的感觉。但是,有一种主要类型的错误我的直觉不是特别好:哪些编程错误会导致调用纯虚函数? 我见过的最常见的错误是从基类构造函数或析构函数调用虚函数。在帮助调试学生代码时,我还应该注意哪些其他事项?
问问题
25499 次
3 回答
28
“我见过的导致这种情况的最常见错误是从基类构造函数或析构函数调用虚函数。”
构造对象时,指向虚拟分派表的指针最初指向最高超类,并且仅在中间类完成构造时更新。因此,您可能会意外调用纯虚拟实现,直到子类(具有自己的覆盖函数实现)完成构造为止。这可能是派生最多的子类,或者介于两者之间的任何地方。
如果您遵循指向部分构造对象的指针(例如,由于异步或线程操作而处于竞争状态),则可能会发生这种情况。
如果编译器有理由认为它知道基类指针指向的真实类型,它可能会合理地绕过虚拟调度。你可能会因为做一些未定义的行为而混淆它,比如重新解释演员表。
在销毁过程中,由于派生类被销毁,虚拟调度表应该被恢复,因此可以再次调用纯虚拟实现。
销毁后,通过“悬空”指针或引用继续使用对象可能会调用纯虚函数,但在这种情况下没有定义的行为。
于 2011-01-06T08:59:17.353 回答
8
以下是可能发生纯虚拟呼叫的几种情况。
- 使用悬空指针- 指针不是有效对象,因此它指向的虚拟表只是可能包含 NULL 的随机内存
- 使用错误
static_cast
类型(或 C 风格的强制转换)的错误转换也可能导致您指向的对象在其虚拟表中没有正确的方法(在这种情况下,至少它确实是一个与前一个选项不同的虚拟表) . - DLL 已被卸载- 如果您持有的对象是在已再次卸载的共享对象文件(DLL,so,sl)中创建的,则现在可以将内存清零
于 2011-01-06T07:32:19.210 回答
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] 中存储的对象不存在。当虚拟表被索引时,没有找到有效的内存位置。因此,会发出运行时错误,说“调用了纯虚函数”。
于 2011-07-22T15:48:58.337 回答