Private virtual method in C++

C++PolymorphismAccess Specifier

C++ Problem Overview


What is the advantage of making a private method virtual in C++?

I have noticed this in an open source C++ project:

class HTMLDocument : public Document, public CachedResourceClient {
private:
    virtual bool childAllowed(Node*);
    virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&);
};

C++ Solutions


Solution 1 - C++

Herb Sutter has very nicely explained it here.

> Guideline #2: Prefer to make virtual functions private. > > This lets the derived classes override the function to customize the > behavior as needed, without further exposing the virtual functions > directly by making them callable by derived classes (as would be > possible if the functions were just protected). The point is that > virtual functions exist to allow customization; unless they also need > to be invoked directly from within derived classes' code, there's no > need to ever make them anything but private

Solution 2 - C++

If the method is virtual it can be overridden by derived classes, even if it's private. When the virtual method is called, the overridden version will be invoked.

(Opposed to Herb Sutter quoted by Prasoon Saurav in his answer, the C++ FAQ Lite recommends against private virtuals, mostly because it often confuses people.)

Solution 3 - C++

Despite all of the calls to declare a virtual member private, the argument simply doesn't hold water. Frequently, a derived class's override of a virtual function will have to call the base class version. It can't if it's declared private:

class Base
{
 private:

 int m_data;

 virtual void cleanup() { /*do something*/ }

 protected:
 Base(int idata): m_data (idata) {}

 public:

 int data() const { return m_data; }
 void set_data (int ndata) { m_data = ndata; cleanup(); }
};

class Derived: public Base
{
 private:
 void cleanup() override
 {
  // do other stuff
  Base::cleanup(); // nope, can't do it
 }
 public:
 Derived (int idata): base(idata) {}
};

You have to declare the base class method protected.

Then, you have to take the ugly expedient of indicating via a comment that the method should be overridden but not called.

class Base
{
 ...
 protected:
 // chained virtual function!
 // call in your derived version but nowhere else.
 // Use set_data instead
 virtual void cleanup() { /* do something */ }
 ...

Thus Herb Sutter's guideline #3...But the horse is out of the barn anyway.

When you declare something protected you're implicitly trusting the writer of any derived class to understand and properly use the protected internals, just the way a friend declaration implies a deeper trust for private members.

Users who get bad behavior from violating that trust (e.g. labeled 'clueless' by not bothering to read your documentation) have only themselves to blame.

Update: I've had some feedback that claims you can "chain" virtual function implementations this way using private virtual functions. If so, I'd sure like to see it.

The C++ compilers I use definitely won't let a derived class implementation call a private base class implementation.

If the C++ committee relaxed "private" to allow this specific access, I'd be all for private virtual functions. As it stands, we're still being advised to lock the barn door after the horse is stolen.

Solution 4 - C++

I first came across this concept while reading Scott Meyers' 'Effective C++', Item 35: Consider alternatives to virtual functions. I wanted to reference Scott Mayers for others that may be interested.

It's part of the Template Method Pattern via the Non-Virtual Interface idiom: the public facing methods aren't virtual; rather, they wrap the virtual method calls which are private. The base class can then run logic before and after the private virtual function call:

public:
  void NonVirtualCalc(...)
  {
    // Setup
    PrivateVirtualCalcCall(...);
    // Clean up
  }

I think that this is a very interesting design pattern and I'm sure you can see how the added control is useful.

  • Why make the virtual function private? The best reason is that we've already provided a public facing method.
  • Why not simply make it protected so that I can use the method for other interesting things? I suppose it will always depend on your design and how you believe the base class fits in. I would argue that the derived class maker should focus on implementing the required logic; everything else is already taken care of. Also, there's the matter of encapsulation.

From a C++ perspective, it's completely legitimate to override a private virtual method even though you won't be able to call it from your class. This supports the design described above.

Solution 5 - C++

I use them to allow derived classes to "fill in the blanks" for a base class without exposing such a hole to end users. For example, I have highly stateful objects deriving from a common base, which can only implement 2/3 of the overall state machine (the derived classes provide the remaining 1/3 depending on a template argument, and the base cannot be a template for other reasons).

I NEED to have the common base class in order to make many of the public APIs work correctly (I'm using variadic templates), but I cannot let that object out into the wild. Worse, if I leave the craters in the state machine- in the form of pure virtual functions- anywhere but in "Private", I allow a clever or clueless user deriving from one of its child classes to override methods that users should never touch. So, I put the state machine 'brains' in PRIVATE virtual functions. Then the immediate children of the base class fill in the blanks on their NON-virtual overrides, and users can safely use the resulting objects or create their own further derived classes without worrying about messing up the state machine.

As for the argument that you shouldn't HAVE public virtual methods, I say BS. Users can improperly override private virtuals just as easily as public ones- they're defining new classes after all. If the public shouldn't modify a given API, don't make it virtual AT ALL in publicly accessible objects.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsilverburghView Question on Stackoverflow
Solution 1 - C++Prasoon SauravView Answer on Stackoverflow
Solution 2 - C++sthView Answer on Stackoverflow
Solution 3 - C++SpencerView Answer on Stackoverflow
Solution 4 - C++PoovenView Answer on Stackoverflow
Solution 5 - C++Zack YezekView Answer on Stackoverflow