a) 重载(overload)。
重载这个名词本身比较简单,函数一共只有三个要素:函数名、形参、返回值。重载的要素是很明确的:函数重名,形参不同(个数或者类型不同都可以)。与返回值无关。但是一定请不要忘记重载另一个非常重要的要素:同一个作用域内才发生重载!
[重载与继承]
关于这二者的关系有两条准则(仔细看,其实就是一条):
如果派生类重定义了重载成员,则通过派生类型只能访问派生类中重定义的那些成员。
如果派生类想通过自身类型使用所有的重载版本,则派生类必须要么重定义所有的重载版本,要么一个也不重定义。
b) 覆盖(override)
同一个作用域内满足一定条件会发生重载。那不同的作用域内呢?只满足一个条件:重名,就一定发生覆盖!(不需要其他的要素。)而且一定是:在较小的那个作用域中,覆盖作用域大的。比如:局部变量一定是覆盖全局变量,全局变量不可见。但涉及到继承,也是一样:在派生类作用域中派生类成员将屏蔽基类成员。即使函数原型不同,基类成员也会被屏蔽。(参见《C++ Primer》中文版第四版P499)。这个实际上也是名字查找的原则之一(参见这篇文章)。
而且这里隐含着另一层意思:基类成员并不是消失,也不是被取代,而只是被屏蔽而不能被调用!所以其实我不喜欢用覆盖这个词,不如用“隐藏”或者“屏蔽”更能表明状况。
而如果派生类中的函数与基类函数原型完全相同,则会发生重定义!这个时候就不是简单意义上的覆盖了,基类函数将在派生类中被取代,也就是消失!
=================================================
下面是《C++ Primer》书中的经典例子。请读者结合以上问题介绍进行理解。
class Base
{
public:
virtual int fcn();
};
class Derived1 : public Base
{
public:
//hides Base::fcn(), this fcn(int) is not virtual
int fcn(int);
//Derived1 inherits definition of Base::fcn()
};
class Derived2 : public Derived1
{
public:
int fcn(int);//nonvirtual function hides Derived1::fcn(int)
int fcn();//redefine virtual Base::fcn()
};
{
public:
virtual int fcn();
};
class Derived1 : public Base
{
public:
//hides Base::fcn(), this fcn(int) is not virtual
int fcn(int);
//Derived1 inherits definition of Base::fcn()
};
class Derived2 : public Derived1
{
public:
int fcn(int);//nonvirtual function hides Derived1::fcn(int)
int fcn();//redefine virtual Base::fcn()
};