I'd guess there is a vtbl created for the abstract class for some internal reason (it might be needed for some sort of run time type info) and something goes wrong and a real object gets it. It's a bug. That alone should say that something that can't happen is.
class Base
{
public:
Base() { reallyDoIt(); }
void reallyDoIt() { doIt(); } // DON'T DO THIS
virtual void doIt() = 0;
};
class Derived : public Base
{
void doIt() {}
};
int main(void)
{
Derived d; // This will cause "pure virtual function call" error
}
class A
{
A *pThis;
public:
A()
: pThis(this)
{
}
void callFoo()
{
pThis->foo(); // call through the pThis ptr which was initialized in the constructor
}
virtual void foo() = 0;
};
class B : public A
{
public:
virtual void foo()
{
}
};
B b();
b.callFoo();
As well as the standard case of calling a virtual function from the constructor or destructor of an object with pure virtual functions you can also get a pure virtual function call (on MSVC at least) if you call a virtual function after the object has been destroyed. Obviously this is a pretty bad thing to try and do but if you're working with abstract classes as interfaces and you mess up then it's something that you might see. It's possibly more likely if you're using referenced counted interfaces and you have a ref count bug or if you have an object use/object destruction race condition in a multi-threaded program... The thing about these kinds of purecall is that it's often less easy to fathom out what's going on as a check for the 'usual suspects' of virtual calls in ctor and dtor will come up clean.
如果你使用 Borland/CodeGear/Embarcadero/Idera C + + Builder,你可以直接实现
extern "C" void _RTLENTRY _pure_error_()
{
//_ErrorExit("Pure virtual function called");
throw Exception("Pure virtual function called");
}
While debugging place a breakpoint in the code and see the callstack in the IDE, otherwise log the call stack in your exception handler (or that function) if you have the appropriate tools for that. I personally use MadExcept for that.
#include <iostream>
using namespace std;
char pool[256];
struct Base
{
virtual void foo() = 0;
virtual ~Base(){};
};
struct Derived: public Base
{
virtual void foo() override { cout <<"Derived::foo()" << endl;}
};
int main()
{
auto* pd = new (pool) Derived();
Base* pb = pd;
pd->~Derived();
pb->foo();
}
堆栈跟踪看起来像:
#0 0x00007ffff7499428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007ffff749b02a in __GI_abort () at abort.c:89
#2 0x00007ffff7ad78f7 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x00007ffff7adda46 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4 0x00007ffff7adda81 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5 0x00007ffff7ade84f in __cxa_pure_virtual () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6 0x0000000000400f82 in main () at purev.C:22