Neil Kirk
Neil Kirk

Reputation: 21773

Is it safe to call a pure virtual function in an abstract constructor/destructor, IF it has a body?

Without the line marked BODY, I know this is not safe. But with it, is this safe?

struct A
{
    virtual ~A() { f(); }

    virtual void f() = 0;
};

void A::f() {} // BODY

struct B : A
{
    void f() {}
};

int main()
{
    delete new B;
}

Working example: http://ideone.com/9bRZ3i

Upvotes: 2

Views: 290

Answers (2)

Potatoswatter
Potatoswatter

Reputation: 137830

If you want to bypass virtual dispatch and call the function body you have defined, you must qualify the function name:

virtual ~A() { A::f(); } // OK.

Otherwise, the call will initiate virtual dispatch, but only to the base class, because the object of derived type has already been destroyed before its bases.

C++11 §12.7/4 directly addresses your question:

Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction or destruction of the class’s non-static data members, and the object to which the call applies is the object (call it x) under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class. If the virtual function call uses an explicit class member access (5.2.5) and the object expression refers to the complete object of x or one of that object’s base class subobjects but not x or one of its base class subobjects, the behavior is undefined.

However, §10.4/6 forbids doing this with a pure virtual function:

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.

So, it's UB.

The effect of "pure virtual" is to hide the function definition from virtual lookup. You will never reach the definition of a pure virtual function from a dynamic dispatch function call, except perhaps as an effect of undefined behavior.

Upvotes: 5

No, that is not safe. While the A constructor (or destructor) is executing the object is of type A, not yet (not anymore) a B object. The call to f() will attempt to dispatch to the (still) pure virtual function and cause undefined behavior. Most implementations will catch this and terminate the application with an error message that indicates that a pure virtual function was called.


After the edit:

The fact that there is a definition for the pure virtual function means that it is legal to call it without going through virtual dispatch. It is still illegal to call a pure virtual function using dynamic dispatch. But you could rewrite the constructor as:

A::~A() { A::f(); }  // qualification disables dynamic dispatch

Without dynamic dispatch, the code becomes valid.

Upvotes: 6

Related Questions