You are designing a base class for a number child classes. You have a function that you can see is common to all the classes that you are designing but may be different in future classes. So you put the common code in the base class and make it virtual so future development can implement different code if need be. Now if it is critical that this default code is checked to make sure it is appropriate for the child class you can make the function pure virtual. Now in any future development the developer has to pay a bit more attention to this function, hence it is safer and less error prone. |
So in the end, it boils down to name convention and lazyness again. Your argument is simply, that it's better to implement the default behaviour in the pure virtual, because then the function feels "the same" and coders don't be tricked into thinking, that other (non-virtual protected) functions
are actually a default implementation, right?
1 2 3 4 5 6 7 8 9
|
struct base
{
virtual void foo() = 0;
};
struct der : base
{
virtual void foo() { base::.... // here the programmer ask himself what the default implementation may be.
// your argument is, he chooses "base::foo" just because it yields the same name hence it seems "natural" to call to this.
};
|
as for the lazyness, it's just easier to not have to declare the second function in base, so go for that?
Well, I have to say that I find these arguments not convincing. I brought up a couple of arguments like
1) the presence of the pure virtual default implementation is not in the interface and hence unexpected. Most developer just are not expecting an implementation of pure virtuals (even knowing that its possible). You have to rely on comments to tell the developer, that it IS in fact possible to call the base class function
2) You can't change the modifier. It will always bear the same as in the base class (most of the time: public).
3) You can only provide one default implementation.
(Note, that 2) and 3) apply for all virtual functions, not only pure virtuals.)
There is only one really showstopper for the case of "use pure virtual implementations" for me, and that's the template thingie. I tried to make a compiling example, but I can't figure out the syntax of how to call a member function of a specific class over a member function pointer. Maybe its not even possible in C++.. (Edit: It's not possible.)
1 2 3 4 5 6 7 8 9 10 11 12 13
|
template <class B, void(B::*fn)()>
struct Caller
{
void call(B& obj)
{
if ( check_whether_allowed_to_call_derrived_classes(obj) )
(obj.*fn)();
else
{
// call obj.B::*fn - version. Couldn't find the syntax. Maybe its not even possible.
}
}
};
|
But hey, guys... I mean.. really... REALLY.. even if someone gets the syntax right here - that's not an argument 99% of the time, is it?
So my resume is still the same: Use non-virtual protected methods with similar name,
except you would plan to make it public anyway (but then you should think of your class design) and you care about too many functions in your class namespace (then you should
really think about your class design. Maybe it's too crowded anyway).
Ciao, Imi.
PS: For more information about this topic, I recommend Scott Meyer, "Effective C++", Item Chapter 36. He doesn't come up with the template-thingie nor with my point 1) above. But he mentioned all the other arguments we had so far, including the description Grey Wolf brought up ;-).