C++ corner case: You can implement pure virtual functions in the base class

In our discussion __purecall, we saw that you can declare a pure virtual function with the = 0 syntax, and if you try to call one of these functions from the base class, you will get the dreaded R6025 - pure virtual function call error.

In that article, I wrote that a pure virtual function is "a method which is declared by the base class, but for which no implementation is provided." That statement is false.

You can provide an implementation for a pure virtual method in C++.

"That's crazy talk," I hear you say.

Okay, let's start talking crazy:

#include <iostream>

class Base {
 Base() { f(); }
 virtual void f() = 0;

class Derived : public Base {
 Derived() { f(); }
 virtual void f() { std::cout << "D"; }

int main(int, char **)
 Derived d;
 return 0;

What happens when the test function constructs a Derived?

Trick question, because you get a linker error when you try to build the project.

There are many questions lurking here, like "Why do I get a linker error?" and "Why isn't it a compiler error?" We'll get back to those questions later. For now, let's get the code to build.

class Base {
 Base() { call_f(); }
 virtual void f() = 0;
 void call_f() { f(); }

Okay, with this change (hiding the call to f inside a function called call_f), the code compiles, so now we can answer the question:

Answer: You get the dreaded purecall error, because the base class constructor has engaged in a conspiracy with the function call_f to call the function f from its constructor. Since f is a pure virtual function, you get the purecall error.

Okay, next question: Why didn't the original code result in a compiler error?

Answer: The compiler is not required to do a full code flow analysis to determine whether you are calling a pure virtual method from a constructor. The language forbids it, but no diagnostic is required and the behavior is undefined.

Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined.

But why did it result in a linker error?

Answer: As we learned during the discussion of __purecall, C++ objects change identity during their construction, and at the point that the Base constructor is running, the object is still a Base, so the final overrider method is Base::f Therefore, when you called f() from the Base constructor, you were actually calling Base::f.

And you never defined Base::f, so the linker complained.

"Wait, I can define Base::f?"

Sure, let's do it. At the end of the program (even after the definition of main) add this code:

void Base::f()
 std::cout << "B";

Now the program compiles, and when you run it, well, we saw that the standard leaves this undefined, so you might crash, or monkeys might fly out of your nose, or the runtime library may go back in time and kill your parents. (We'll see in a future article how undefined behavior can lead to time travel. How's that for a teaser!)

But one implementation might generate this program output:


This particular implementation decided not to try very hard to detect the case where you are calling Base::f during the constructor and just lets the call happen, and it ends up calling the method you defined later.

"But if I'm not allowed to call the pure virtual function from a constructor or destructor, and if I call the method after construction, it always calls the version of the function that the derived class overrode, then how could this code ever execute at all (legitimiately)? In other words, what conforming program could ever print the letter B?"

The function cannot be called implicitly, but it can be called explicitly:

class Base {
 Base() { /* f(); */ }
 virtual void f() = 0;

void Base::f()
 std::cout << "B";

class Derived : public Base {
 Derived() { f(); }
 virtual void f() { std::cout << "D"; Base::f(); }

int main(int, char **)
 Derived d;
 return 0;

First, we got rid of the illegal call to f() in the base class constructor (to keep our code legit). Next, we adjusted our override version of f so that it calls the base class method after doing some custom work.

This time, the program prints DB, and the code is perfectly legitimate this time. No undefined behavior, nothing up my sleeve.

What happened here?

The derived class constructor called the f method, which maps to Derived::f. That function prints the letter D, and then it calls the base class version Base::f explicitly. The base class version then prints the letter B.

This is actually nothing new; this is how overridden methods work in general. The only wrinkle here is that the base class method can be called only via explicit qualification; there is no way to call it implicitly.

This was a rather long-winded way of calling out a weird corner case in C++ that most people don't even realize exists: A pure virtual function can have an implementation.

Comments (40)
  1. Joshua says:

    Raymond's not kidding about the undefined behavior. The platforms that leave this undefined are also likely to have no memory protection. You might call a NULL.

  2. Ben says:

    @Joshua, Calling a null and getting SEGV and dumping core, IS memory protection. Putting a null in the vtable is a good choice.

    Some platforms instead use a wrapper function that produces a sensible diagnostic and calls abort. Also a reasonable choice.

  3. Joshua says:

    @Ben: I believe I said the ones that end up with calling a NULL or some other hideously undefined result such as uninitialized memory in the vptr are often the ones that don't have any memory protection so calling a NULL does something but not what you want.

  4. Medinoc says:

    In short, the reason we get a linker error in the first case (instead of a runtime error), is that the constructor calls f() directly (or at least, tries to) instead of going through the vtable (and getting __purecall instead) ?

    On the other hand, call_f() is not a constructor, so it goes through the vtable…

    [Thanks for filling in that gap. I realized just now that I forgot to answer that question. -Raymond]
  5. Misha says:

    >  What happens when the test function constructs a Derived?

    You mean the main function, right?

  6. Matt says:


    Unless your C++ is in kernel mode, and you're running on Windows7.

    In which case an attacker might have put some shellcode at NULL. And you just called it over a security boundary from Ring-0, giving it control of your machine, and letting it take your credit card numbers and install drivers all over your system.

    Every Single Windows Patch Marked As Critical is caused by undefined behavior in the language. Don't fall into the trap of thinking that undefined behavior will fail safe. It typically won't.

  7. Alex says:

    Batman will always regret the day he had to implement a pure virtual function in its base class.

  8. Tyler Reddun says:

    This is a corner case, but there is just enough rare places where it can be useful (@Chris had a great example of that) that maybe it should be codified in some future version of the spec. That way you'll no longer run the risk of corrupting memory, summing Candle Jack or having your hard drive

  9. Anon says:

    '…the base class constructor has engaged in a conspiracy… with the function call_f…'

    This sounds like it should be in an advertisement for one of Russinovich's Zero Day novels.

  10. JM says:

    @Matt: an attacker who can put code at location 0 is already on the other side of the proverbial airtight hatch. It is also not true that every critical security vulnerability is caused by undefined behavior — if only it were that clear-cut. And finally, you seem to be accusing Ben of holding opinions he never stated. In short, if your post had been an editorial in a magazine, I would be asking for my money back.

    It is very true that undefined behavior is bad, though, and programs should not contain it. I think we can reach consensus on that.

    [Actually, it's not true that they are on the wrong side of the airtight hatch. User-mode code could map memory at offset 0, and then kernel code can be tricked into accessing it. You now have elevation from user mode to kernel mode. -Raymond]
  11. Joshua says:

    @JM: On some Microchip processors, 0 (I forget if their compiler maps NULL to 0 or not) when interpreted as a code segment pointer (Harvard architecture) is the address of the IVT, which consists of jump instructions. You just raised interrupt 0, whatever it may be.

    On x86 in 16 bit mode, this executes the IVT offsets as instructions, which is pretty badly undefined. If DOS is loaded, there's a JMP instruction a few dozen bytes down which will get executed if IP is still aligned correctly. This results in entering the DOS syscall gateway with trashed registers (registers are syscall arguments), then continue from your code (C calling convention = caller cleans up the stack).

  12. Chris says:

    This is mainly useful for pure virtual destructors. If you need to make your class pure virtual, but don't have any method in particular that you need overridden, a pure virtual destructor will do that. However, the destructor still needs a definition, and it *is* called implicitly.

  13. JM says:

    @Joshua: it would be nice to get a machine where this is treated as calling location 0, and location 0 contains wonderful instructions that corrupt your program state (or some *other* program's state, even better) but don't terminate it, so you end up with an undebuggable mess. Unfortunately that's unlikely — if you have a tinkertoy with no memory protection, calling random instructions is far, far more likely to outright crash or hang the machine than to do something interesting instead. Ah, so much for joy and wonder.

  14. xyz says:

    In regard to the linked article:

    Did we ever finish determining if init-methods or constructors are the only right thing?

    And there are easy methods around adding size to every allocation to get it for gc, which can be easily optimised to no_vtable for common cases where no virtual is called during construction.

  15. Myria says:

    @JM: Windows 7 and earlier allow unprivileged user-mode applications to allocate memory at address 0 within their own process space by calling VirtualAlloc or MapViewOfFile with an nonzero address that gets aligned down to zero; the traditional way is to use (void*) 1.  This feature is intentionally used by NTVDM to allocate the interrupt table for V86 mode.  Because the Windows NT kernel runs with userspace directly accessible to the kernel, null pointers are dangerous, because that memory is then user-controlled.  Windows 8 blocks this by limiting address 0 allocation to NTVDM, which secondarily limits it to 32-bit x86 Windows only.

    @Raymond: Why does C++ allow pure virtual functions to have an implementation?  This seems silly.

  16. Jim says:

    @Myria: You realise this was the subject of the article, right? Anyway, to repeat it, it's to allow explicit calls from derived classes, or (as Chris says) to allow destructors (which certainly need an implementation) to be pure virtual.

    The only case I've seen of this is to allow pure virtual destructors. It was a bit of an idiom in the code that I saw it; it was used fairly regularly to mean "abstract class (but with no naturally abstract methods)". It feels very suspect to me. If there are no other virtual methods in this class, surely nobody should be manipulating objects (including destroying them) through a pointer of this type anyway? Perhaps you could change inheritance to composition, which is usually an improvement where reasonable possible. Alternatively, if there are some implemented virtual methods but they all "need a bit more" implementation from derived classes, that seems like a rather fragile design.

  17. Jim says:

    Oh, and slightly off-topic for this article (but not much), since no one mentioned it in the previous one:

    The most common cause of "pure virtual method called" bugs, in my experience, is not something happening deep in the constructor's call stack. Instead it is a symptom of calling a virtual method on an object that's been destroyed. As the destructor is run the vtable is updated in the opposite way to construction: it moves up the inheritance chain until finally it's left at the root class. This is left in place when the object is destroyed (there's no point in setting it to something else, because the memory should never be read again) so if you access it after that, and by chance the memory hasn't been reused, you'll use the base class virtual methods.

  18. Neil says:

    OK, I'd better ask the question in reverse:

    Why does a virtual function with an implementation need to be pure? (The example given is to make a class abstract, although I'm not sure why making all the constructors protected doesn't suffice.)

  19. JM says:

    @Raymond: Well don't I feel like pond scum now. But Raymond, isn't it wrong that user code is allowed to do that if it can cause problems like that? And is it fair to say the kernel is "tricked" when what we mean is that the kernel contains bugs that cause it to access location 0 at times where it shouldn't?

    @Myra: OK, that answers my question. I'm glad Windows 8 fixes this hole. That the kernel can access the memory isn't worrisome, IMO — it will inevitably need to, somehow. Even disallowing code access and copying all data to safe buffers first doesn't mean you can't stuff data in those buffers that exploits a bug (though it helps, obviously).

    @Joshua: I'm happy to learn that there's actually a far better chance of continuing the program in a corrupted state than I thought! Thanks, I learned something new. (I was thinking of *really* dinky setups like an 8-bit 6502; it is far more likely to encounter an instruction that will hang the processor or invoke an NMI which resets things rather than a jump instruction, let alone one that takes you back to where you came from.)

    [In the original design, it was legal for user mode code to whatever it wanted, and people who wrote code that ran in kernel mode need to be understand that 0 was a potentially valid address. In practice, this means that if you find a null pointer bug in kernel, you can use the null mapping trick to turn it into EoP. So yes, what's really happening is that you are exploiting a null pointer bug in kernel. "Trickery" was an interpretive statement on my part as to your motivation. -Raymond]
  20. Joshua says:

    @Neil: Indeed. That's how I do it.

    Some people go farther and protect the class from trying to instantiate itself.

  21. John Doe says:

    Imagine that the pure virtual method is declared in a published header, but the implementation is defined in a private source code file.

    There, the actual implementation has an actual virtual method for itself that the audience thinks it does not. It may be a useful technique in a handful of cases.

  22. Simon says:

    Herb Sutter: Does it ever make sense to make a function pure virtual, but still provide a body?


  23. Deduplicator says:

    @John Doe:

    What do you think hiding the implementation of your pure virtual function buys you? People can extend your class anyway, unless its the dtor.

  24. John Doe says:

    @Deduplicator, but they can't instance it directly.

  25. Deduplicator says:

    @John Doe:

    Nobody can instantiate an abstract class. So what? And what exatly do you think hiding the implementation in an obscure location buys you?

    BTW: Having the implementation in a (bunch of) private source file is standard practice. If its published, you name it opensource, otherwise closedsource.

  26. smf says:

    > In that article, I wrote that a pure virtual function is "a method which is declared by the base class,

    > but for which no implementation is provided." That statement is false.

    > You can provide an implementation for a pure virtual method in C++.

    Yes the statement is false. The pure virtual function tells the compiler that you're not going to be providing an implementation, so the class is abstract and an instance cannot be created. You have to derive a class that implements all the pure virtual functions before you can create one.

    The linker you use doesn't appear to care that you told the compiler you wouldn't be providing an implementation but then you did. If the spec doesn't say that you can do this (I haven't checked) then another compiler might take the = 0 as an implementation and then it's linker might complain that you've provided two conflicting implementations. Microsofts linker does allow multiple conflicting implementations but MINGW tools do not allow them (I was recently tripped up by this, although not in relation to pure virtual calls).

    [Implementing pure virtual methods is allowed by the standard [class.abstract and basic.def.odr] and every compiler must support it. Declaring a virtual method pure does not mean "I will not provide an implementation." It means "I require derived classes to override this method." In practice, you rarely want one without the other. -Raymond]
  27. Alex Cohn says:

    Note that making constructors "protected" does not protect your class: C++ does not enforce this protection, it is only marked as such in the header files that the user can easily manipulate, or even write

    #define protected public

    #include <whatever>

    [If you're looking for protection against malicious object usage, then C++ is the wrong language. Even without editing the header file, you can get around the enforcement. *(int *)((char *)this + magicOffset) = 3; // hahahah I modified a private member! -Raymond]
  28. Harry Johnston says:

    While being aware of this stuff is obviously important to the developer (because they may need to debug problems caused by it) from a language design perspective I think this can all be filed under "reasons why allowing subclasses is a bad idea".  

    (Of course, this presumes that interfaces and unnamed member objects can effectively serve the same purposes as subclasses, given properly-designed code.  I haven't yet seen a counterexample, but OTOH I haven't looked very hard.)

  29. GWO says:

    @AlexCohn "#define private public" may well work, but violates the one-definition-rule, so you've got undiagnosed undefined the moment you hit main()

    Compilers are allowed to change the relative ordering of members with different access, so there's no guarantee that

    class foo



      int x;


      int y;



    class foo2



      int x;

      int y;


    have the same layout.

  30. John Doe says:

    @Harry Johnston, but by redirecting to member objects as to replicate "base class behavior inheritance", you have to worry about object identity. Sometimes that means simple redirecting methods, but other times it means wrapping everything and a trip to Mars.

    This reminds me a lot of COM aggregation. But for it to be useful, it should be encouraged. And higher-level languages should make it easier, e.g. stating the coclass used to instantiate the object that will "implement" an interface by default, i.e. for which an interface's methods redirect to if not explicitly overridden.

  31. Simon Farnsworth says:


    In my copy of the C++ Standard 2003, section 10.4 Abstract classes, paragraph 2 says "A pure virtual function need be defined only if explicitly called with the qualified-id syntax (5.1)". This in turns means that you can define a pure virtual function, but that it will only be used if you explicitly call it with a qualified call (of the form A::b(), instead of just plain b()).

    You are also permitted to make a function into a pure virtual as you derive from a class, so:

    class A



       void foo();


    class B



       void foo() = 0;


    is legit.

  32. John Doe says:

    @Deduplicator, the answer to "So what?" is exactly that you want to keep the class abstract to not allow direct instantiation. Most probably, because the class was designed with that specific behavior ruled out. It forces the "user" (a developer here) to override the pure virtual methods, whether they are actually implemented or not, whether they call the base method even knowing it was declared pure virtual.

    Commenter Simon gave a very good link explaining this kind of stuff. In other languages, you simply mark the class as abstract without these… "tricks".

    For the other part, I wasn't even implying that "private" source files (e.g. *.c/*.cpp) were either open or closed source, much less "obscure places". It's usual for headers files to serve as public definition files or public interfaces. Notwithstanding proper documentation, Of Course™. If it's there but it's not documented, it might not be there the next version, or it might be different.

  33. Evan says:

    "We'll see in a future article how undefined behavior can lead to time travel. How's that for a teaser!"

    I'm so excited I'm going to go invoke some undefined behavior in the hopes it will make that time arrive sooner!

  34. alegr1 says:

    A member function access may be (at least it was) part of the decorated name. If you mangle the class declaration and call a library function that otherwise would not be acessible, the linker may not actually find it.

  35. Harry Johnston says:

    @John Doe: I'm sorry, I don't understand what you mean.  The way I see it, eliminating subclassing means precisely that you *don't* have to worry about object identify.  If you've got a pointer to a Foo, you know that the object is indeed a Foo, and you know exactly what code will be called when you invoke a member function.

  36. John Doe says:

    @Harry Johnston, when you say "eliminating subclassing", do you mean eliminating type hierarchy or implementation inheritance? The first means you can't tell the interfaces an object implements by looking at its type (but maybe like Go, by looking at its methods). The second means interfaces can inherit from interfaces and classes may implement interfaces (ok, pure abstract classes), but (non-pure abstract) classes may not inheric other (non-pure abstract) classes.

    I was referring to the second.

    So, to immitate implementation inheritance, you must wrap an existing class's instance, i.e. an object of the type you're "subclassing". The identity problem happens when you have referential usage of objects provided as arguments to methods. For instance, if you're wrapping an existing object which has events, either that object participates in your object's identity, or you have to wrap the events getters and setters, and you have to set the inner object's events to these wrappers. The wrappers then call the actual event handlers with our object as "this", not the inner object.

    In COM, aggregation works because the only interface pointer that dictates identity is the one for IUnknown. However, it only works for aggregatable objects, so for the rest (majority?), you have to go through hoops (if you really need to).

    In C++, you usually don't twist at this level so much and you usually just assume that any same-class pointer comparison is enough for identity. The inner object is never the outer object. If your event handler code or tests assert for identity (I'm being invoked by the object on which I registered), you have a problem unless you somehow wrap.

  37. Harry Johnston says:

    @John Doe:

    Type hierarchy is what I primarily want to eliminate: that is, given a class object I want the class definition to unambiguously determine the methods and interfaces the object implements, and exactly which code gets used when you call them.  If you have an interface, of course, all that you know is that the object is of some class which implements the interface in question.  (Except that, if the language supports class references, it would be sensible to be able to take an interface and get a class reference for the underlying object.)

    As for implementation inheritance, this divides into several different cases (probably including one or more I've not thought about).

    One case is where the inner object is not designed to be nested, and where it is natural for the outer object to contain the inner one.  This typically means you are extending or using the inner functionality rather than modifying it.  In this case implementation inheritance amounts to syntactic sugar so that the compiler can automatically convert Alice->x to Alice->Bob.x if the programmer so desires.  I'm happy with this.

    For event-driven code, syntactic sugar should be all you need provided that Alice does not need to modify the events that Bob is sending or receiving.  Alice's getFooSender function can return the FooSender interface for the member instance of Bob, or perhaps some more syntactic sugar can take care of it.  Carol, receiving the events, only ever knows about Bob.  (And vice versa if Bob is the receiver and Carol the sender.)

    The second case is where the inner object is designed to be nested, and changes its behavior depending on the object it is nested within.  I think this is best managed via some sort of plug-in approach; the outer object installs one or more plug-ins that the inner object calls out to.  I don't see why this can't be done with interfaces just as well as with virtual functions, although you might want some more syntactic sugar to eliminate the boilerplate that would otherwise be required during construction.

    For event-driven code, Bob might call methods such as preSendFoo and/or postSendFoo contained in the plug-in interface provided by the outer object, allowing the outer object to veto, modify, or respond to the event.

    Yet another case is where the inner object is not designed to be modified but the outer object wants to modify it anyway; for example, if Alice wants to modify the way Bob processes events without actually standing between Bob and Carol.  I'm not sure if that's the scenario you're talking about or not.  I'm not convinced that this is sound programming practice.  If my hypothetical idealized language were to support it at all, it would probably be via some sort of templating, i.e., telling the compiler "create a class called Alice which has all of the same source code as Bob except for the bits I explicitly change".  From Carol's point of view, and in terms of the binary, Alice and Bob would be entirely unrelated.

  38. GregM says:

    Harry, it sounds like you want "final"


  39. Harry Johnston says:

    @GregM: not really; "final" doesn't address type hierarchy, and besides, it's optional. :-)

  40. GregM says:

    Well, of course it's optional.  How could it possibly be any other way?  How does it not address type hierarchy?  It makes it so you can't derive from the classes, exactly as you described.  Mark every one of your classes with final, and you get exactly what you asked for, "that is, given a class object I want the class definition to unambiguously determine the methods and interfaces the object implements, and exactly which code gets used when you call them."

Comments are closed.

Skip to main content