Yes. It's sometimes (not always!) a great idea. For example, suppose
all Shape objects have a common algorithm for printing, but this algorithm
depends on their area and they all have a potentially different way to compute
their area. In this case Shape's
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Yes, it is a different strategy. Yes, there really are two different basic ways to use virtual functions:
For emphasis, the above list is a both/and situation, not an either/or
situation. In other words, you don't have to choose between these two
strategies on any given class. It's perfectly normal to have method
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
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:
Code using public overloaded virtuals:
Improving this via the Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals idiom:
Here's an overview of the original code:
Public? | Inline? | Virtual? | Overloaded? |
Yes | No | Yes | Yes |
Here's an overview of the improved code that uses the Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals idiom:
Public? | Inline? | Virtual? | Overloaded? |
Yes | Yes | No | Yes |
No | No | Yes | No |
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.)
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Almost never.
Protected virtuals are okay, but private virtuals are usually a net loss. Reason: private virtuals confuse new C++ programmers, and confusion increases cost, delays schedule, and degrades risk.
New C++ programmers get confused by private virtuals because they think a private virtual cannot be overridden. After all, a derived class cannot access members that are private in its base class so how, they ask, could it override a private virtual from its base class? There are explanations for the above, but that's academic. The real issue is that almost everyone gets confused the first time they run into private virtuals, and confusion is bad.
Unless there is a compelling reason to the contrary, avoid private virtuals.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Because that would be very dangerous, and C++ is protecting you from that danger.
The rest of this FAQ gives a rationale for why C++ needs to protect you from that danger, but before we start that, be advised that you can get the effect as if dynamic binding worked on the this object even during a constructor via The Dynamic Binding During Initialization Idiom.
First, here is an example to explain exactly what C++ actually does:
The output from the above program will be:
The rest of this FAQ describes why C++ does the above. If you're happy merely knowing what C++ does without knowing why, feel free to skip this stuff.
The explanation for this behavior comes from combining two facts:
Now some of you are still curious, saying to yourself, "Hmmmm, but I still
wonder why the this object is merely of type Base during
Here's how: imagine for the moment that calling
So fortunately the C++ language doesn't let this happen: it makes sure any
call to
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Yes: the Dynamic Binding During Initialization idiom (AKA Calling Virtuals During Initialization).
To clarify, we're talking about this situation:
This FAQ shows some ways to simulate dynamic binding as if the calls made in Base's constructor dynamically bound to the this object's derived class. The ways we'll show have tradeoffs, so choose the one that best fits your needs, or make up another.
The first approach is a two-phase initialization. In Phase I, someone calls
the actual constructor; in Phase II, someone calls an "init" method on the
object. Dynamic binding on the this object works fine during Phase II, and
Phase II is conceptually part of construction, so we simply move some
code from the original
The only remaining issues are determining where to call Phase I and where to call Phase II. There are many variations on where these calls can live; we will consider two.
The first variation is simplest initially, though the code that actually wants to create objects requires a tiny bit of programmer self-discipline, which in practice means you're doomed. Seriously, if there are only one or two places that actually create objects of this hierarchy, the programmer self-discipline is quite localized and shouldn't cause problems.
In this variation, the code that is creating the object explicitly executes
both phases. When executing Phase I, the code creating the object either
knows the object's exact class (e.g.,
Note: Phase I often, but not always, allocates the object from the heap. When
it does, you should store the pointer in some sort of
managed pointer, such as a
The second variation is to combine the first two lines of the joe_user
function into some create function. That's almost always the right
thing to do when there are lots of joe_user-like functions. For
example, if you're using some kind of factory, such as a registry and
the virtual constructor idiom, you could move those
two lines into a static method called
This simplifies all the joe_user-like functions (a little), but more
importantly, it reduces the chance that any of them will create a Derived
object without also calling
If you're sufficiently clever and motivated, you can even eliminate
the chance that someone could create a Derived object without also calling
The next approach does not rely on a two-phase initialization, instead using a
second hierarchy whose only job is to house methods
Let's call the base class of this second hierarchy Helper, and its
derived classes Helper1, Helper2, etc. The first step is to
move
Next, remove
We then define
Finally we change Derived's constructor to pass a (perhaps temporary) object
of an appropriate Helper derived class to Base's constructor (using
the init list syntax). For example, Derived would
pass an instance of Helper2 if it happened to contain the behaviors
that Derived wanted for methods
Note that Derived can pass values into the Helper derived class's
constructor, but it must not pass any data members that actually live
inside the this object. While we're at it, let's explicitly say that
Of course the choice of which Helper derived class could be made out in the joe_user-like function, in which case it would be passed into the Derived ctor and then up to the Base ctor:
If the Helper objects don't need to hold any data, that is, if each is merely a collection of its methods, then you can simply pass static member functions instead. This might be simpler since it entirely eliminates the Helper hierarchy.
The Derived class is also easy to implement:
As before, the functionality for
A final approach is to use templates to "pass" the functionality into the derived classes. This is similar to the case where the joe_user-like functions choose the initializer-function or the Helper derived class, but instead of using function pointers or dynamic binding, it wires the code into the classes via templates.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
C++ is protecting you from yourself. What you are trying to do is very dangerous, and if the compiler did what you wanted, you'd be in worse shape.
For rationale of why C++ needs to protect you from that danger, read FAQ
[23.5]. The situation during a destructor is
analogous to that during the constructor. In particular, within the
Read FAQ [23.5] for more insight on this matter.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
It's legal, but it ain't moral.
Experienced C++ programmers will sometimes redefine a non-virtual function for efficiency (e.g., if the derived class implementation can make better use of the derived class's resources) or to get around the hiding rule. However the client-visible effects must be identical, since non-virtual functions are dispatched based on the static type of the pointer/reference rather than the dynamic type of the pointed-to/referenced object.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
It means you're going to die.
Here's the mess you're in: if Base declares a member function
Here's how you get out of the mess: Derived must have a using declaration of the hidden member function. For example,
If the using syntax isn't supported by your compiler, redefine the
hidden Base member function(s), even if they are
non-virtual. Normally this re-definition merely calls the hidden
Base member function using the
Note: the hiding problem also occurs if class Base declares a method
Note: warnings are not part of the standard, so your compiler may or may not give the above warning.
Note: nothing gets hidden when you have a base-pointer. Think about it: what a derived class does or does not do is irrelevant when the compiler is dealing with a base-pointer. The compiler might not even know that the particular derived class exists. Even if it knows of the existence some particular derived class, it cannot assume that a specific base-pointer necessarily points at an object of that particular derived class. Hiding takes place when you have a derived pointer, not when you have a base pointer.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
If you get a link error of the form "
The compiler typically creates a magical data structure called the "virtual table" for classes that have virtual functions (this is how it handles dynamic binding). Normally you don't have to know about it at all. But if you forget to define a virtual function for class Fred, you will sometimes get this linker error.
Here's the nitty gritty: Many compilers put this magical "virtual table" in the
compilation unit that defines the first non-inline virtual function in the
class. Thus if the first non-inline virtual function in Fred is
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
This is known as making the class "final" or "a leaf." There are three ways to do it: an easy technical approach, an even easier non-technical approach, and a slightly trickier technical approach.
The (easy) technical approach is to make the class's constructors private and to use the Named Constructor Idiom to create the objects. No one can create objects of a derived class since the base class's constructor will be inaccessible. The "named constructors" themselves could return by pointer if you want your objects allocated by new or they could return by value if you want the objects created on the stack.
The (even easier) non-technical approach is to put a big fat ugly
comment next to the class definition. The comment could say, for example,
A slightly trickier technical approach is to exploit virtual inheritance. Since the most derived class's ctor needs to directly call the virtual base class's ctor, the following guarantees that no concrete class can inherit from class Fred:
Class Fred can access FredBase's ctor, since Fred is a friend of FredBase, but no class derived from Fred can access FredBase's ctor, and therefore no one can create a concrete class derived from Fred.
If you are in extremely space-constrained environments (such as an embedded
system or a handheld with limited memory, etc.), you should be aware that the
above technique might add a word of memory to
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
This is known as making the method "final" or "a leaf." Here's an easy-to-use
solution to this that gives you 90+% of what you want: simply add a comment
next to the method and rely on code reviews or random maintenance activities
to find violators. The comment could say, for example,
The advantages to this technique are (a) it is extremely easy/fast/inexpensive to use, and (b) it is quite effective in practice. In other words, you get 90+% of the benefit with almost no cost lots of bang per buck.
(I'm not aware of a "100% solution" to this problem so this may be the best you can get. If you know of something better, please let me know, cline@parashift.com. But please do not email me objecting to this solution because it's low-tech or because it doesn't "prevent" people from doing the wrong thing. Who cares whether it's low-tech or high-tech as long as it's effective?!? And nothing in C++ "prevents" people from doing the wrong thing. Using pointer casts and pointer arithmetic, people can do just about anything they want. C++ makes it easy to do the right thing, but it doesn't prevent espionage. Besides, the original question (see above) asked for something so people won't do the wrong thing, not so they can't do the wrong thing.)
In any case, this solution should give you most of the potential benefit at almost no cost.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
E-mail the author
[ C++ FAQ Lite
| Table of contents
| Subject index
| About the author
| ©
| Download your own copy ]
Revised Mar 1, 2006