摘自《高质量程序设计指南》林锐
重载与覆盖
成员函数被重载的特征是:
-具有相同的作用域(即同一个类定义中)--如果位于不同的作用域,则为隐藏。
-函数名字相同。
-参数类型/顺序或数目不同(包括const参数和非const参数)。
-virtual关键字可有可无。
覆盖是指派生类重新实现(或者改写)了基类的成员函数,其特征是:
-不同的作用域(分别位于派生类和基类中)。
-函数名称相同。
-参数列表相同。
-基类函数必须是虚函数。(用virtual关键字)。--如果没有virtual关键字,则为隐藏。
注:覆盖:使用虚函数virtual 一般不用具体的实现函数virtual fun() = 0;即故意要让继承者重新实现函数功。
而隐藏则可以暂时在子类里屏蔽了基类的功能函数,重新实现函数名相同,但参数可以不同。
综上,覆盖是一种特殊的隐藏。
程序示例1
#include<iostream>
using namespace std;
class Base{
public:
void f(int x){cout<<"Base::f(int)="<<x<<endl;}
void f(float x){cout<<"Base::f(float)="<<x<<endl;}
virtual void g(void){cout<<"Base::g(void)."<<endl;}
};
class Derived:public Base{
public:
virtual void g(void){cout<<"Derived::g(void)."<<endl;}
};
int main(void)
{
Derived d;
Base *pb=&d;
pb->f(42); //Base::f(int)=42
pb->f(3.14f); //Base::f(float)=3.14
pb->g(); //Derived::g(void).
return 0;
}
有时候,程序员希望作“跨越类边界的重载”,但是重载机制只能作用于同一作用域中,C++提供类
另一种机制--隐藏,它是指派生类的成员函数遮蔽了与其同名的基类成员函数。
虽然还没达到完美的要求,但C++使用了这种策略(原因《The Designed and Evolution of C++》).
示例2
#include<iostream>
using namespace std;
class Base{
public:
virtual void f(float x){ cout<<"Base::f(float)="<<x<<endl;}
void g(float x){cout<<"Base::g(float)="<<x<<endl;}
void h(float x){cout<<"Base::h(float)="<<x<<endl;}
};
class Derived:public Base{
public:
virtual void f(float x){ cout << "Derived::f(float)"<<x<<endl; }
void g(int x){ cout << "Derived::g(int)"<<x<<endl; }
void h(float x){ cout << "Derived::h(float)"<<x<<endl;}
};
int main()
{
Derived d;
Base *pb=&d;
Derived *pd=&d;
//程序的行为仅仅依赖于对象的真实类型
pb->f(3.14f); //动态绑定:Derived::f(float)=3.14
pd->f(3.14f); //动态绑定:Derived::f(float)=3.14
//不好:程序的行为依赖于指针的静态模型
pb->g(3.14f); //静态绑定:Base::g(float)=3.14
pd->g(3.14f); //静态绑定:Derived::g(float)=3
//此处3.14被强制转化为一个int类型的临时变量,而本意是想使用跨越类边界的重载
//不好:程序的行为依赖于指针的静态模型
pb->h(3.14f); //静态绑定:Base::h(float)3.14
pd->h(3.14f); //静态绑定:Derived::g(float)=3
return 0;
}
总结:覆盖是隐藏的一种特殊,它改写类基类的成员函数,但是隐藏却没被改写成员函数。
而重载是根据参数的不同,区分使用同一作用域中同名的函数。
另外,
如果确实想使用所谓的“跨越类边界的重载”,可以在派生类定义中的任何地方显示的使用using关键字,
示例2中红色处:
写成 using Base ::g;
void g(int x){ cout << "Derived::g(int)"<<x<<endl; }
或者使用调用传递
void g(float x){Base::g(x);}
void g(int x){ cout << "Derived::g(int)"<<x<<endl; }
显然使用using关键字比较省事。
参数的默认值的常见错误
http://blog.csdn.net/xydkd/article/details/7194669