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?
-
others maybe calling it from some member functions of the base class, what else could be there? but then that is not an error! :| – Nawaz Jan 06 '11 at 07:26
-
That's really what my question is. :-) There may not be another way to trigger a pure virtual call, and my main question is whether or not there is one. – templatetypedef Jan 06 '11 at 07:27
4 Answers
"The most common error I've seen that causes this is calling a virtual function from a base class constructor or destructor."
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.

- 102,968
- 15
- 177
- 252
-
Actually, virtual calls are disabled in constructors and destructors - [explained here](https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctors) - therefore, calls are not virtual and linker error happens. Any non-virtual dispatch will caus linker error. But I agree for partially constructed (or corrupted) objects when virtual table is simply incorrect. However, these situations require dynamic tricks which is not seen by compiler (threading as mentioned, reinterpret_cast, etc.). – uvsmtid Nov 10 '15 at 17:24
-
@uvsmtid: "Actually" implies you're correcting some mistaken assertion I've made, but I didn't mention constructors and destructors, only *construction* and *destruction*. Construction consists of base class and non-static data member initialisation before the constructor's initialisation list and body are processed; it's pretty much the same in reverse during destruction. Dispatch to pure virtual functions can happen as illustrated [here](http://coliru.stacked-crooked.com/a/29b4fa463e39e277), without threading, async, `reinterpret_cast` etc.. – Tony Delroy Nov 11 '15 at 03:50
-
Separately, from the link you provide or otherwise - I can't imagine how linker errors manifest. Could you please show me with some code? Perhaps the coliru site I've linked to in the comment above, ideone.com or whatever you prefer.... Cheers – Tony Delroy Nov 11 '15 at 03:52
Here are a few cases in which a pure virtual call can happen.
- Using a dangling pointer - the pointer isn't of a valid object so the virtual table it points to is just random memory which may contain NULL
- Bad cast using a
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). - DLL has been unloaded - If the object you're holding on to was created in a shared object file (DLL, so, sl) which has been unloaded again the memory can be zeroed out now

- 110,860
- 49
- 189
- 262
-
-
2
-
@GMan, pretty much yes, perhaps it doesn't deserve a separate bullet point but it's easier to diagnose than the general case – Motti Jan 06 '11 at 07:40
-
@ephemient, I don't know about that, AFIK using VC generates a pure virtual call for this scenario. – Motti Jan 06 '11 at 07:41
-
3@Motti: Funny you mention that. VC defines a function `_purecall` (which just aborts with diagnostic) and places it into the vtable slots for pure virtual methods. It's not the quite same as following a function pointer to NULL. – ephemient Jan 06 '11 at 15:41
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.

- 478
- 3
- 16
-
It happened to me when I chose to not have a class as an ATL Object after having it declared as such. I forgot to delete the _ATL_NO_VTABLE and it was quite the difficult error to spot. – Daniel Bauer Apr 14 '23 at 07:08
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:
std::vector <DerivedClass> objContainer;
if (!objContainer.empty())
const BaseClass& objRef = objContainer.front();
// Do some processing using objRef and then you erase the first
// element of objContainer
objContainer.erase(objContainer.begin());
const std::string& name = objRef.name();
// -> (name() is a pure virtual function in base class,
// which has been implemented in DerivedClass).
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".

- 378,754
- 76
- 643
- 1,055

- 1,194
- 4
- 16
- 30
-
Yes I tried with and got an error "pure virtual method called". What error are you seeing? – cppcoder Jun 11 '15 at 17:48
-
The example is incomplete, so I didn't reconstruct it yet. But as I guess, you are calling a virtual function for a dangeling pointer, I'll try this soon. BTW: this is undefined behaviour and so it might crash in a different way. – Wolf Jun 12 '15 at 05:23