什么可以导致C++中的纯虚函数调用?

tem*_*def 33 c++ pure-virtual

我教了一个C++编程类,我已经看到了足够多的错误类型,我对如何诊断常见的C++错误感觉很好.但是,有一种主要类型的错误,我的直觉并不是特别好:编程错误导致调用纯虚函数? 我见过的最常见的错误导致这是从基类构造函数或析构函数调用虚函数.在帮助调试学生代码时,还有其他我应该注意的事项吗?

Ton*_*roy 28

"我见过的最常见的错误导致这是从基类构造函数或析构函数调用虚函数."

构造对象时,指向虚拟调度表的指针最初瞄准最高超类,并且它仅在中间类完成构造时更新.因此,您可能会意外地调用纯虚拟实现,直到子类(具有自己的重写函数实现)完成构造.这可能是派生最多的子类,也可能是介于两者之间的任何位置.

如果您按照指向部分构造的对象的指针(例如,由于异步或线程操作而处于竞争状态),则可能会发生这种情况.

如果编译器有理由认为它知道指针到基类指向的实际类型,则它可以合理地绕过虚拟调度.您可能会通过执行具有未定义行为(如重新解释转换)的操作来混淆它.

在销毁期间,应该在销毁派生类时恢复虚拟调度表,因此可以再次调用纯虚拟实现.

在销毁之后,通过"悬空"指针或引用继续使用对象可以调用纯虚函数,但在这种情况下没有定义的行为.


Mot*_*tti 8

以下是一些纯虚拟调用可能发生的情况.

  1. 使用悬空指针 - 指针不是有效对象,因此它指向的虚拟表只是随机内存,可能包含NULL
  2. 坏投static_cast了错误的类型(或C样式转换),还可以使你指向不具有在其虚表的正确方法的对象(在这种情况下,至少它确实不同于以往的选项的虚拟表) .
  3. 已卸载DLL - 如果您要保留的对象是在已再次卸载的共享对象文件(DLL,so,sl)中创建的,则内存现在可以清零

  • @Motti:有趣的是你提到了.VC定义了一个函数`_purecall`(只是通过诊断中止)并将其放入vtable插槽中以获得纯虚方法.它与跟随NULL的函数指针不完全相同. (3认同)
  • purecall处理程序通常是一个特殊的函数,而不是NULL. (2认同)