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.