类定义中大致有两种函数——普通函数和虚函数。如果对一个类继承并且对其中的成员函数重新进行定义,也可以分为两种情况:
1、在派生类的定义中明确地定义操作和返回类型,称之为普通成员函数的重定义(redefining);
2、对虚函数的重定义成为重写(overriding);
下面的程序是摘自《Thinking in C++》上的一段,可以用来解释发生在函数重定义过程中的名字隐藏(这里的名字指的是函数的名字):
#include <iostream>
#include <string>
using namespace std;
class Base{
public:
int f() const
{
cout<<"Base::f()\n";
return 1;
}
int f(string) const {return 1;}
void g() {}
};
class Derived1 : public Base{
public:
void g() const {}
};
class Derived2 : public Base{
public:
int f() const
{
cout<<"Derived2::f()\n";
return 2;
}
};
class Derived3 : public Base{
public:
void f() const
{
cout<<"Derived3::f()\n";
}
};
class Derived4 : public Base{
public:
int f(int) const
{
cout<<"Derived4::f()\n";
return 4;
}
};
int main()
{
string s("hello");
Derived1 d1;
int x = d1.f();
d1.f(s);
Derived2 d2;
x = d2.f();
d2.f(s);
return 0;
}
首先,Derived1只重定义了父类的g()函数,没有对f()函数做任何的改变,因此调用f()的时候会自动调用父类的f()。并且f(s)在Derived1中也是可以使用的。
对于Derived2,它重定义了f()函数,而没有重定义f(s)函数,但是在这里却只能调用f()而不能调用f(s),即f(s)被隐藏了。
如果对Derived2修改一下,即重定义f()函数,也重定义f(s)函数,则两种都可以调用。
对于Derived3,它没有重定义基类中名为f的任何函数,而是通过修改返回值类型自己重新定义了一个名为f的函数,导致基类中的两个名为f的函数均不能被调用,即均被隐藏了。
对于Derived4,它没有重定义基类中名为f的任何函数,而是通过修改参数自己重新定义一个名为f的函数,导致基类中的两个名为f的函数均不能被调用,即均被隐藏了。
因此,可以得出一个结论:任何时候重新定义了基类中的一个重载函数,在新类之中所有其他的版本则被自动隐藏,除非在子类中全部重定义。
而对于虚函数的重写则有一点不同,即编译器不允许我们改变重定义过的函数的返回值类型(除了是将从基类引用或指针改为子类引用或指针),其它的则与重定义遵循一样的规则。这是为什么呢?在《Thinking in C++》上是这么说的:“因为编译器必须保证我们能够动态地通过基类调用函数,并且如果基类希望f()返回一个int值,则f()的派生类版本必须保持约定,否则将会出问题”。