我有时会注意到计算机崩溃的程序出现错误:"纯虚函数调用".
当无法创建抽象类的对象时,这些程序如何编译?
如果您尝试从构造函数或析构函数进行虚函数调用,则会导致它们.由于您无法从构造函数或析构函数进行虚函数调用(派生类对象尚未构造或已被销毁),因此它调用基类版本,在纯虚函数的情况下,它不会不存在.
(在这里查看现场演示)
class Base { public: Base() { doIt(); } // DON'T DO THIS virtual void doIt() = 0; }; void Base::doIt() { std::cout<<"Is it fine to call pure virtual function from constructor?"; } class Derived : public Base { void doIt() {} }; int main(void) { Derived d; // This will cause "pure virtual function call" error }
除了从具有纯虚函数的对象的构造函数或析构函数调用虚函数的标准情况之外,如果在对象被销毁后调用虚函数,则还可以获得纯虚函数调用(至少在MSVC上) .显然,尝试这样做是一件非常糟糕的事情,但是如果你正在使用抽象类作为接口而你搞砸了,那么你可能会看到它.如果您使用引用的计数接口并且您有一个引用计数错误或者如果您在多线程程序中有对象使用/对象破坏竞争条件,则可能更有可能...关于这些类型的纯粹调用的事情是它的通常不太容易理解正在发生的事情,因为检查ctor和dtor中虚拟呼叫的"常见嫌疑人"会变得干净.
为了帮助调试这些类型的问题,您可以在各种版本的MSVC中替换运行时库的purecall处理程序.您可以通过使用此签名提供自己的功能来执行此操作:
int __cdecl _purecall(void)
并在链接运行时库之前链接它.这使您可以控制检测到纯调用时发生的情况.一旦掌握了控制权,就可以做一些比标准处理程序更有用的事情.我有一个处理程序,可以提供purecall发生位置的堆栈跟踪; 请参阅此处:http://www.lenholgate.com/blog/2006/01/purecall.html了解更多详情.
(注意,您也可以调用_set_purecall_handler()在某些版本的MSVC中安装处理程序).
通常当您通过悬空指针调用虚函数时 - 很可能该实例已被销毁.
还有更多"创造性"的原因:也许你已经设法切掉了实现虚拟功能的对象部分.但通常只是实例已经被破坏了.