7 Answers
7

They can result if you try to make a virtual function call from a constructor or destructor. Since you can't make a virtual function call from a constructor or destructor (the derived class object hasn't been constructed or has already been destroyed), it calls the base class version, which in the case of a pure virtual function, doesn't exist.

In the general case can't catch it since the flow from the ctor can go anywhere and anywhere can call the pure virtual function. This is Halting problem 101.
–
shooshSep 19 '08 at 4:20

3

Answer is slightly wrong: a pure virtual function may still be defined, see Wikipedia for details. Correct phrasing: might not exist
–
MSaltersSep 19 '08 at 10:46

2

I think this example is too simplistic: The doIt() call in the constructor is easily devirtualised and dispatched to Base::doIt() statically, which just causes a linker error. What we really need is a situation in which the dynamic type during a dynamic dispatch is the abstract base type.
–
Kerrek SBApr 5 '12 at 9:41

2

This can be triggered with MSVC if you add an extra level of indirection: have Base::Base call a non-virtual f() which in turn calls the (pure) virtual doIt method.
–
Frerich RaabeMar 5 '14 at 14:20

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.

To help with debugging these kinds of problems you can, in various versions of MSVC, replace the runtime library's purecall handler. You do this by providing your own function with this signature:

int __cdecl _purecall(void)

and linking it before you link the runtime library. This gives YOU control of what happens when a purecall is detected. Once you have control you can do something more useful than the standard handler. I have a handler that can provide a stack trace of where the purecall happened; see here: http://www.lenholgate.com/blog/2006/01/purecall.html for more details.

(Note you can also call _set_purecall_handler() to install your handler in some versions of MSVC).

Thanks for the pointer about getting a _purecall() invocation on a deleted instance; I wasn't aware of that, but just proved it to myself with a little test code. Looking at a postmortem dump in WinDbg I thought I was dealing with a race where another thread was trying to use a derived object before it had been fully constructed, but this shines a new light on the issue, and seems to better fit the evidence.
–
Dave RuskeMar 6 at 16:37

One other thing I'll add: the _purecall() invocation that normally occurs on calling a method of a deleted instance will not happen if the base class has been declared with the __declspec(novtable) optimization (Microsoft specific). With that, it's entirely possible to call an overridden virtual method after the object has been deleted, which could mask the problem until it bites you in some other form. The _purecall() trap is your friend!
–
Dave RuskeMar 6 at 16:52

That's useful to know Dave, I've seen a few situations recently where I wasn't getting purecalls when I thought I should be. Perhaps I was falling foul of that optimisation.
–
Len HolgateMar 6 at 18:22

Usually when you call a virtual function through a dangling pointer--most likely the instance has already been destroyed.

There can be more "creative" reasons, too: maybe you've managed to slice off the part of your object where the virtual function was implemented. But usually it's just that the instance has already been destroyed.

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.

Pure speculation

edit: looks like I'm wrong in the case in question. OTOH IIRC some languages do allow vtbl calls out of the constructor destructor.

It is not a bug in the compiler, if that is what you mean.
–
ThomasSep 19 '08 at 4:20

Your suspicion is right - C# and Java allow this. In those languages, bohjects under construction do have their final type. In C++, objects change type during construction and that's why and when you can have objects with an abstract type.
–
MSaltersSep 19 '08 at 10:42

ALL abstract classes, and real objects created derived from them, need a vtbl (virtual function table), listing which virtual functions should be called on it. In C++ an object is responsible for creating its own members, including the virtual function table. Constructors are called from base class to derived, and destructors are called from derived to base class, so in an abstract base class the virtual function table is not yet available.
–
fuzzyTewJul 17 '09 at 11:00

At least it can't be reproduced on my vc2008,the vptr does point to A's vtable when first initialized in A's contructor, but then when B is fully initialized, the vptr is changed to point to B's vtable, which is ok
–
Baiyan HuangMar 7 '10 at 2:45

I had this essentially happen to me today obviously not true, because simply wrong: a pure virtual function is called only when callFoo() is called within a constructor (or destructor), because at this time the object is still (or already) at A stage. Here is a running version of your code without the syntax error in B b(); - the parentheses make it a function declaration, you want an object.
–
WolfJun 11 at 11:26