views:

5449

answers:

6

I sometimes notice programs that crash on my computer with the error: "pure virtual function call".

How do these programs even compile when an object cannot be created of an abstract class?

A: 

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.

BCS
It is not a bug in the compiler, if that is what you mean.
Thomas
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.
MSalters
*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.
fuzzyTew
+20  A: 

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.

class Base
{
public:
    Base() { 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
}
Adam Rosenfield
Any reason why the compiler couldn't catch this, in general?
Thomas
I don't see any technical reason why the compiler couldn't catch this.
Brian R. Bondy
GCC gives me a warning only:test.cpp: In constructor ‘Base::Base()’:test.cpp:4: warning: abstract virtual ‘virtual void Base::doIt()’ called from constructorBut it fails at link time.
Thomas
Ironically, I had this exact thing happen to me today. In a slightly more tricky fashion.
1800 INFORMATION
vc++ fails at link time too...>test.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall Base::doIt(void)" (?doIt@Base@@UAEXXZ)
Brian R. Bondy
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.
shoosh
Answer is slightly wrong: a pure virtual function may still be defined, see Wikipedia for details. Correct phrasing: *might* not exist
MSalters
+5  A: 

Here is a great explanation of what can cause this:

http://www.artima.com/cppsource/pure_virtual.html

Jeff Hillman
+2  A: 

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.

Braden
A: 

Here is a sneaky way for it to happen. I had this essentially happen to me today.

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();
1800 INFORMATION
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
lz_prgmr
+5  A: 

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/archives/000623.html for more details.

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

Len Holgate