The question is from C++ faq.
http://www.parashift.com/c++-faq-lite/protected-virtuals.html
Code using public overloaded virtuals:
class Base {
public:
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 {
public:
void f(int x) { f_int(x); } ← non-virtual
void f(double x) { f_dbl(x); } ← non-virtual
protected:
virtual void f_int(int);
virtual void f_dbl(double);
};
The author said:
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.
But I do not understand what the author said on how this idiom improve 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.
Why does this solve the hiding problem? From what I understand, name hiding has nothing to do whether the member function is ‘virtual’ or not. If a derived class of ‘base’ rewrites a function f(), it will still hide the f(int) and f(double), right?
From this idiom all I can see is that author change the ‘base’ virtual f() to non virtual, and put helper functions f_int(), f_dbl() in ‘protected virtual’, like the name of idiom said. It does nothing good yet but in contrary eliminates possibility of dynamic binding from base class pointer/reference. What is the true benefit of this idiom?
Update
Kerrek, are you saying this? I do not fully understand the second paragraph of your answer. Could you give an example?
class base {
public:
virtual void f(int x);
virtual void f(double x);
}
class derived : public base {
public:
virtual int f(int x); // oops, will hide base::f(int x) AND base::f(double x)
}
base *bp = new base();
base *dp = new derived();
bp->f(int i); // ok
dp->f(int i); // surprise!
dp->f(double d); // compile error!
class Base {
public:
void f(int x) { f_int(x); }
void f(double x) { f_dbl(x); }
protected:
virtual void f_int(int);
virtual void f_dbl(double);
};
class derived : public base {
public:
// nothing to override here 'cause f() is non virtual
protected:
// because f_int() and f_dbl are unique names, override or hide f_int() will not affect f_dbl()?
virtual int f_int(int); // oops, will hide base::f(int x), but developer may want this on purpose
// no effect on f_dbl(), which is good
}
base bobj;
derived dobj;
bobj.f(int i); // ok
dobj.f(double d); // ok
If a derived class declares
void f(int), then it overrides the virtual function, and thevirtualspecifier is implied. If a derived class declaresint f(int), it hides the base function. I gather that you’re familiar with this.The problem comes when you want others to develop code based on your base class. With the naive approach, each derived class must be careful to add the correct override so as not to accidentally hide the function and get a working, but wrong program (i.e. the user says
f()but gets the wrong thing). With the “public non-virtual” idiom, the user always callsf()in confidence, and the library developer can override only those parts that she’s interested in by overriding a uniquely named, protected function, without having to touch a name that may affect other users.