混迹于C++ 之重载与覆盖(还有隐藏)

摘自《高质量程序设计指南》林锐

重载与覆盖

成员函数被重载的特征是:

-具有相同的作用域(即同一个类定义中)--如果位于不同的作用域,则为隐藏。

-函数名字相同。

-参数类型/顺序或数目不同(包括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


        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值