What is the point of a private pure virtual function?

BeeBand picture BeeBand · Oct 19, 2010 · Viewed 48.2k times · Source

I came across the following code in a header file:

class Engine
{
public:
    void SetState( int var, bool val );
    {   SetStateBool( int var, bool val ); }

    void SetState( int var, int val );
    {   SetStateInt( int var, int val ); }
private:
    virtual void SetStateBool(int var, bool val ) = 0;    
    virtual void SetStateInt(int var, int val ) = 0;    
};

To me, this implies that either the Engine class or a class derived from it, has to provide the implementation for those pure virtual functions. But I didn't think derived classes could have access to those private functions in order to reimplement them - so why make them virtual?

Answer

Maciej Hehl picture Maciej Hehl · Oct 20, 2010

The question in the topic suggest a pretty common confusion. The confusion is common enough, that C++ FAQ advocated against using private virtuals, for a long time, because confusion seemed to be a bad thing.

So to get rid of the confusion first: Yes, private virtual functions can be overridden in the derived classes. Methods of derived classes can't call virtual functions from the base class, but they can provide their own implementation for them. According to Herb Sutter, having public non-virtual interface in the base class and a private implementation that can be customized in the derived classes, allows for better "separation of the specification of interface from the specification of the implementation's customizable behavior". You can read more about it in his article "Virtuality".

There is however one more interesting thing in the code you presented, that deserves some more attention, in my opinion. The public interface consists of a set of overloaded non-virtual functions and those functions call non-public, non-overloaded virtual functions. As usual in the C++ world it is an idiom, it has a name and of course it is useful. The name is (surprise, surprise!)

"Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals"

It helps to properly manage the hiding rule. You can read more about it here, but I'll try to explain it shortly.

Imagine, that virtual functions of the Engine class are also its interface and it is a set of overloaded functions that is not pure virtual. If they were pure virtual, one could still encounter the same problem, as described below, but lower in the class hierarchy.

class Engine
{
public:
    virtual void SetState( int var, bool val ) {/*some implementation*/}
    virtual void SetState( int var, int val )  {/*some implementation*/}
};

Now let's assume you want to create a derived class and you need to provide a new implementation only for the method, that takes two ints as arguments.

class MyTurbochargedV8 : public Engine
{
public:
    // To prevent SetState( int var, bool val ) from the base class,
    // from being hidden by the new implementation of the other overload (below),
    // you have to put using declaration in the derived class
    using Engine::SetState;

    void SetState( int var, int val )  {/*new implementation*/}
};

If you forgot to put the using declaration in the derived class (or to redefine the second overload), you could get in trouble in the scenario below.

MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);

If you didn't prevent the hiding of the Engine members, the statement:

myV8->SetState(5, true);

would call void SetState( int var, int val ) from the derived class, converting true to int.

If the interface is not virtual and the virtual implementation is non-public, like in your exmaple, the author of the derived class has one less problem to think about and can simply write

class MyTurbochargedV8 : public Engine
{
private:
    void SetStateInt(int var, int val )  {/*new implementation*/}
};