当你调用一个成员函数时,编译器就会运用查找规则来查找可能性最大的选项。查找限定在一个范围之内。在类继承的情况下,这就意味着子类所申明的成员函数可能会隐藏与之同名的基类虚成员函数——甚至当这两个函数的签名(signature)不同时,情况也是如此。例如:
class Base
{
public:
virtual void f(int);
};
class Derived : public Base
{
public:
void f(void*);
};
int main()
{
Derived d;
d.f(10); //#1 编译错误
}
尽管Base类有着一个叫着f()、参数为int型的成员函数,但是在#1处的函数调用还是发生了一个错误。这是因为搜索算法在当前范围(在本例中,当前范围即为Derived类)内找到了一个名字匹配的函数。
如果编译器在当前范围内找不到匹配名字,它就会继续搜索。然而,一旦查找算法在当前范围内找到匹配名字(如本例这种情况),它就停止搜索并开始重载。因为Derived::f()的参数是void *类型而不是int类型,因此重载失败。
某些编译器会在这种情况下给出警告信息:“子类的成员函数隐藏了基类函数”。这条警告信息表示你不应该在子类申明名字与基类函数名字相同的成员函数——除非它们都是虚函数并且拥有相同的签名;否则,你并没有重载基类函数——你只是隐藏了基类函数而已。
本文作者Danny Kalev 是一个系统分析家、软件工程师,在C++和面向对象设计方面有着14年的专业经验。