什么会导致 C++ 中的纯虚函数调用?
我教授 C++ 编程课程,并且见过足够多的错误类别,因此我对如何诊断常见的 C++ 错误有很好的感觉。然而,有一种主要类型的错误,我的直觉不是特别好:什么编程错误会导致调用纯虚函数?我见过的导致这种情况的最常见错误是调用虚函数来自基类构造函数或析构函数的函数。在帮助调试学生代码时我还应该注意其他事项吗?
I teach a C++ programming class and I've seen enough classes of errors that I have a good feeling for how to diagnose common C++ bugs. However, there's one major type of error for which my intuition isn't particularly good: what programming errors cause calls to pure virtual functions? The most common error I've seen that causes this is calling a virtual function from a base class constructor or destructor. Are there any others I should be aware of when helping debug student code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
当构造一个对象时,指向虚拟调度表的指针最初指向最高超类,并且仅在中间类完成构造时才更新。因此,您可能会意外地调用纯虚拟实现,直到子类(具有自己的重写函数实现)完成构造。这可能是最派生的子类,或介于两者之间的任何子类。
如果您跟踪指向部分构造的对象的指针(例如,由于异步或线程操作而导致竞争条件),则可能会发生这种情况。
如果编译器有理由认为它知道指向基类的指针所指向的真实类型,则它可以合理地绕过虚拟分派。您可能会通过执行一些未定义的行为(例如重新解释强制转换)来混淆它。
在销毁期间,虚拟调度表应该在派生类被销毁时恢复,因此可以再次调用纯虚拟实现。
销毁后,通过“悬空”指针或引用继续使用对象可能会调用纯虚函数,但在这种情况下没有定义的行为。
When an object is constructed, the pointer to the virtual dispatch table is initially aimed at the highest superclass, and it's only updated as the intermediate classes complete construction. So, you can accidentally call the pure virtual implementation up until the point that a subclass - with its own overriding function implementation - completes construction. That might be the most-derived subclass, or anywhere in between.
It might happen if you follow a pointer to a partially constructed object (e.g. in a race condition due to async or threaded operations).
If a compiler has reason to think it knows the real type to which a pointer-to-base-class points, it may reasonably bypass the virtual dispatch. You might confuse it by doing something with undefined behaviour like a reinterpret cast.
During destruction, the virtual dispatch table should be reverted as derived classes are destroyed, so the pure virtual implementation may again be invoked.
After destruction, continued use of the object via "dangling" pointers or references may invoke the pure virtual function, but there's no defined behaviour in such situations.
以下是可能发生纯虚拟调用的几种情况。
的 NULL 错误转换 static_cast
到错误的类型(或 C 风格的强制转换)也可能导致您指向的对象在其虚拟表中没有正确的方法(在这种情况下至少它确实是与之前的选项不同的虚拟表)。Here are a few cases in which a pure virtual call can happen.
static_cast
to the wrong type (or C-style cast) can also cause the object you point to to not have the correct methods in its virtual table (in this case at least it really is a virtual table unlike the previous option).除了其他答案之外:
如果在没有 vtable 的情况下声明派生类,也可能会发生这种情况。
对于 Visual Studio,即如果它是使用 __declspec(novtable) 或 _ATL_NO_VTABLE 定义的。使用 MFC 技术时可能会发生这种情况。
如果类以这种方式定义,则 vtable 将填充 _purecall。
In addition to the other answers:
It can also happen if the derived class is declared without vtable.
For Visual Studio, that is, if it is defined with __declspec(novtable) or _ATL_NO_VTABLE for example. It can happen when working with the MFC technology.
If the class is defined that way, the vtable will be filled with _purecall.
例如,当对象的引用或指针指向 NULL 位置,并且您使用对象引用或指针调用类中的虚函数时,就会发生这种情况。例如:
此时objContainer[0]中存储的对象不存在。当虚拟表被索引时,没有找到有效的内存位置。因此,会发出运行时错误,指出“调用了纯虚函数”。
This can happen for example when the reference or pointer to an object is pointing to a NULL location, and you use the object reference or pointer to call a virtual function in the class. For example:
At this point object stored in objContainer[0] does not exist. When the virtual table is indexed, no valid memory location is found. Hence, a run time error is issued saying "pure virtual function called".