C++ FAQ Celebrating Twenty-One Years of the C++ FAQ!!!
(Click here for a personal note from Marshall Cline.)
Section 23:
[23.3] Should I use protected virtuals instead of public virtuals?

Sometimes yes, sometimes no.

First, stay away from always/never rules, and instead use whichever approach is the best fit for the situation. There are at least two good reasons to use protected virtuals (see below), but just because you are sometimes better off with protected virtuals does not mean you should always use them. Consistency and symmetry are good up to a point, but at the end of the day the most important metrics are cost + schedule + risk, and unless an idea materially improves cost and/or schedule and/or risk, it's just symmetry for symmetry's sake (or consistency for consistency's sake, etc.).

The cheapest + fastest + lowest risk approach in my experience ends up resulting in most virtuals being public, with protected virtuals being used whenever you have either of these two cases: the situation discussed in FAQ [23.2], or the situation discussed in FAQ [23.9].

The latter deserves some additional commentary. Pretend you have a base class with a set of overloaded virtuals. To make the example easy, pretend there are just two: virtual void f(int) and virtual void f(double). The idea of the Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals idiom is to change the public overloaded methods to non-virtuals, and make those call protected non-overloaded virtuals.

Code using public overloaded virtuals:

class Base {
  virtual void f(int x);     may or may not be pure virtual
  virtual void f(double x);  may or may not be pure virtual
Improving this via the Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals idiom:
class Base {
  void f(int x)    { f_int(x); }   non-virtual
  void f(double x) { f_dbl(x); }   non-virtual
  virtual void f_int(int);
  virtual void f_dbl(double);
Here's an overview of the original code:


Here's an overview of the improved code that uses the Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals idiom:


The reason I and others use this idiom is to make life easier and less error-prone for the developers of the derived classes. Remember the goals stated above: schedule + cost + risk? Let's evaluate this Idiom in light of those goals. From a cost/schedule standpoint, the base class (singular) is slightly larger but the derived classes (plural) are slightly smaller, for a net (small) improvement in schedule and cost. The more signicant improvement is in risk: the idiom packs the complexity of properly managing the hiding rule into the base class (singular). This means the derived classes (plural) more-or-less automatically handle the hiding rule, so the various developers who produce those derived classes can remain almost completely focused on the details of the derived classes themselves — they need not concern themselves with the (subtle and often misunderstood) hiding rule. This greatly reduces the chance that the writers of the derived classes will screw up the hiding-rule.

With apologies to Spock, the good of the many (the derived classes (plural)) outweighs the good of the one (the base class (singular)).

(See FAQ [23.9] for why you need to be careful about overriding some-but-not-all of a set of overloaded methods, and therefore why the above makes life easier on derived classes.)