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

来源:互联网 发布:淘宝卖家后台 编辑:程序博客网 时间:2024/04/28 01:37

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

重载与覆盖

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

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

-函数名字相同。

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


        

原创粉丝点击