What Is the Point of a Private Pure Virtual Function

What is the point of a private pure virtual function?

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*/}
};

Purpose of private pure virtual function?

So in general the pattern is to implement the public non-virtual function and the private or protected virtual function, it looks like you have researched this already, but this is generally known as the Template Method Pattern, with more explanations by Herb Sutter here and here.

Whether to make it pure virtual or not depends on your requirements, sometimes there is absolutely no default behavior that makes sense, or you want to force all the subclasses to implement their own version of this virtual function. Sometimes an empty implementation does make sense. Then provide, but what happens is that other implementors might forget to customize their classes, not implementing the virtual class for which you provided a default behavior. It is really a case by case decision that you will have to make.

There are some corner cases in which you will want to provide an implementation for a pure virtual function, Herb Sutter again, lists two, one to provide default behavior but force derived classes to conciously call, and the other is to protect against compiler issues that might get a pure virtual function called.

There are various concerns comming together at the point where your problem lies, in general make virtual functions private or protected, called by a public function (again Template Method Pattern). If derived classes don't need to call a superclasses implementation, make it private. If you want to implement default behavior make it protected and implement the default behavior in a higher class. If you want to force subclasses to implement their own function (independent of wether there is default behavior or not) make it pure virtual.

C++: Private virtual functions vs. pure virtual functions

One benefit is in implementing the template method pattern:

class Base {

public :
void doSomething() {
doSomething1();
doSomething2();
doSomething3();
}
private:
virtual void doSomething1()=0;
virtual void doSomething2()=0;
virtual void doSomething3()=0;
};

class Derived : public Base {
private:
virtual void doSomething1() { ... }
virtual void doSomething2() { .... }
virtual void doSomething3() { .... }
}

This allows the derived classes to implement each piece of a certain logic, while the base class determines how to put these pieces together. And since the pieces don't make sense by themselves, they are declared private and so hidden from client code.

Why would a virtual function be private?

See this Herb Sutter article as to why you'd want to do such a thing.

Is there any difference between a private and protected pure virtual function?

Are there any scenarios where a protected pure virtual makes any
sense?

I think that you mean private here (instead of protected), but think I understand your point. In fact, the access type of a pure virtual can be overridden in derived classes. Here's an example that might help you see the difference between a private and protected pure virtual:

class Parent
{
protected: virtual void foo() = 0;
private: virtual void bar() = 0;
public: void test() { foo(); bar(); }
};

class Child : public Parent
{
public: void test2() { foo(); /* bar(); // cannot be called here */ }
};

class GrandChild : public Child
{
// access types here can be anything for this example
public: void foo() { cout << "foo" << endl; }
public: void bar() { cout << "bar" << endl; }
};

Why private virtual member function of a derived class is accessible from a base class

First, as @Eljay notes - printImpl() is a method, albeit virtual, of the Base class. So, it's accessible from the base class. Derived merely provides a different implementation of it. And the whole point of virtual functions is that you can call a subclass' override using a base class reference or pointer.

In other words, private only regards access by subclasses; it's meaningless to keep something private from a class' base class: If a method is at all known to the base class, it must be a method of the base class... a virtual method.

Having said all that - note that the Derived version of printImpl() is effectively inaccessible from print() - when it's invoked within the base class constructor. This is because during that call, the constructed vtable is only that of Base, so printImpl points to Base::printImpl.

I thought private member functions could be called ONLY from the member functions of the same class

And indeed, print() is a member of Base, which invokes printImpl() - another method of Base.

Virtual/pure virtual explained

From Wikipedia's Virtual function
...

In object-oriented programming, in languages such as C++, and Object Pascal, a virtual function or virtual method is an inheritable and overridable function or method for which dynamic dispatch is facilitated. This concept is an important part of the (runtime) polymorphism portion of object-oriented programming (OOP). In short, a virtual function defines a target function to be executed, but the target might not be known at compile time.

Unlike a non-virtual function, when a virtual function is overridden the most-derived version is used at all levels of the class hierarchy, rather than just the level at which it was created. Therefore if one method of the base class calls a virtual method, the version defined in the derived class will be used instead of the version defined in the base class.

This is in contrast to non-virtual functions, which can still be overridden in a derived class, but the "new" version will only be used by the derived class and below, but will not change the functionality of the base class at all.

whereas..

A pure virtual function or pure virtual method is a virtual function that is required to be implemented by a derived class if the derived class is not abstract.

When a pure virtual method exists, the class is "abstract" and can not be instantiated on its own. Instead, a derived class that implements the pure-virtual method(s) must be used. A pure-virtual isn't defined in the base-class at all, so a derived class must define it, or that derived class is also abstract, and can not be instantiated. Only a class that has no abstract methods can be instantiated.

A virtual provides a way to override the functionality of the base class, and a pure-virtual requires it.

Is it dangerous to create pure virtual function of a virtual function?

From ISO IEC 14882 2014:

§ 10.4 says:

5 [ Note: An abstract class can be derived from a class that is not abstract, and a pure virtual function may
override a virtual function which is not pure. —end note ]

So It's perfectly possible to do that.

Example of use case:

You can have a basic type, that is implemented as a concrete type (base class). Now, for subtypes, we might be in a need of further additional information. So, we can have an abstract intermediate object to meet our needs.

Class with implementation of pure virtual function

Pure virtual functions are the virtual functions whose implementation must be provided by the derived class. This is one of the reason to make your virtual function pure, so that derived class must have it's implementation.

virtual void function()=0 is pure virtual function where =0 indicates it's purity.

When you have a pure virtual function in a class, you are not suppose to create a instance of class. (Otherwise making function pure virtual doesn't make much sense). Such a class is abstract class.

Now, there might be some cases where you want to have your own implementation of pure virtual function so that derived class may directly use it. Hence we provide body of pure virtual function in some cases.

If you want to create an instance of that class, don't make your virtual function pure.



Related Topics



Leave a reply



Submit