Why a virtual call to a pure virtual function from a constructor is UB and a call to a non-pure virtual function is allowed by the Standard?

Belloc picture Belloc · Feb 8, 2012 · Viewed 9.6k times · Source

From 10.4 Abstract Classes parag. 6 in the Standard :

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

Assuming that a call to a non-pure virtual function from a constructor (or destructor), is allowed by the Standard, why the difference ?

[EDIT] More standards quotes about pure virtual functions:

§ 10.4/2 A virtual function is specified pure by using a pure-specifier (9.2) in the function declaration in the class definition. A pure virtual function needs be defined only if called with, or as if with (12.4), the qualified-id syntax (5.1). ... [ Note: A function declaration cannot provide both a pure-specifier and a definition —end note ]

§ 12.4/9 A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined.

Some questions that need answering are:

  • Where the pure virtual function has not been given an implementation, should this not be a compiler or linker error instead?

  • Where the pure virtual function has been given an implementation, why can it not be well-defined in this case to invoke this function?

Answer

Chris Dodd picture Chris Dodd · Feb 8, 2012

Because a virtual call can NEVER call a pure virtual function -- the only way to call a pure virtual function is with an explicit (qualified) call.

Now outside of constructors or destructors, this is enforced by the fact that you can never actually have objects of an abstract class. You must instead have an object of some non-abstract derived class which overrides the pure virtual function (if it didn't override it, the class would be abstract). While a constructor or destructor is running, however, you might have an object of an intermediate state. But since the standard says that trying to call a pure virtual function virtually in this state results in undefined behavior, the compiler is free to not have to special case things to get it right, giving much more flexibility for implementing pure virtual functions. In particular, the compiler is free to implement pure virtuals the same way it implements non-pure virtuals (no special case needed), and crash or otherwise fail if you call the pure virtual from a ctor/dtor.