问题来自 C++ 常见问题解答。
http://www.parashift.com/c++-faq-lite/protected-virtuals.html
使用公共重载虚拟的代码:
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
};
通过 Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals 成语改进这一点:
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);
};
作者说:
Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals 习语的想法是将公共重载方法更改为非虚拟,并使那些调用受保护的非重载虚拟。
但我不明白作者对这个成语如何提高风险所说的话:
该成语将正确管理隐藏规则的复杂性打包到基类(单数)中。这意味着派生类(复数)或多或少会自动处理隐藏规则,因此生成这些派生类的各种开发人员几乎可以完全专注于派生类本身的细节——他们不需要关心 (微妙且经常被误解)隐藏规则。这大大降低了派生类的编写者搞砸隐藏规则的机会。
为什么这解决了隐藏问题?据我了解,名称隐藏与成员函数是否“虚拟”无关。如果“base”的派生类重写了函数 f(),它仍然会隐藏 f(int) 和 f(double),对吗?
从这个习语中我只能看到作者将'base'虚拟f()更改为非虚拟,并将辅助函数f_int(),f_dbl()放在'protected virtual'中,就像成语的名字所说的那样。它还没有什么好处,但相反消除了从基类指针/引用动态绑定的可能性。这个成语的真正好处是什么?
更新
克雷克,你是在说这个吗?我不完全理解你回答的第二段。你能举个例子吗?
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