C++ 重载、覆盖、隐藏

(1) 重载的几个函数必须在同一个类中, 覆盖的函数必须在有继承关系的不同的类中, 隐藏也必须在有继承关系的不同的类中;


(2) 覆盖的函数前必须加关键字Virtual;重载和Virtual没有任何瓜葛,加不加都不影响重载的运作,隐藏对virtual可有可无


(3) 覆盖的几个函数必须函数名、参数、返回值都相同;


(4) 重载的函数必须函数名相同,参数不同, 返回值也要相同;


      重载的函数必须函数名相同,参数不同。参数不同的目的就是为了在函数调用的时候编译器能够通过参数来判断程序是在调用的

哪个函数。这也就很自然地解释了为什么函数不能通过返回值不同来重载,因为程序在调用函数时很有可能不关心返回值,编译器就无

法从代码中看出程序在调用的是哪个函数了。
  
     "隐藏"是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
 
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。   


(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。  

 

 

 

[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. #include <QCoreApplication>  
  2. #include <QDebug>  
  3.   
  4. #include <iostream>  
  5.   
  6. using namespace std;  
  7.   
  8. class Base  
  9.   
  10. {  
  11.   
  12. public:  
  13.   
  14.   
  15.     virtual void f(float x){ qDebug() << "Base::f(float) " << x ; }  
  16.   
  17.   
  18.     void g(float x){ qDebug() << "Base::g(float) " << x ; }  
  19.   
  20.   
  21.     void h(float x){ qDebug() << "Base::h(float) " << x ; }  
  22.   
  23.   
  24. };  
  25.   
  26.   
  27. class Derived : public Base  
  28.   
  29. {  
  30.   
  31. public:  
  32.   
  33.   
  34.     virtual void f(float x){ qDebug() << "Derived::f(float) " << x ; }  
  35.     //重载  
  36.     void g(int x){ qDebug() << "Derived::g(int) " << x ; }  
  37.   
  38.     void g(float x) { qDebug() << "Derived::g(float)" << x ; }  
  39.   
  40.     void h(int x){ qDebug() << "Derived::h(int) " << x ; }  
  41.   
  42. };  
  43.   
  44. int main(int argc, char *argv[])  
  45. {  
  46.     QCoreApplication a(argc, argv);  
  47.   
  48.     Derived d;  
  49.   
  50.   
  51.     Base *pb = &d;  
  52.   
  53.   
  54.     Derived *pd = &d;  
  55.   
  56.   
  57.     // Good 行为 ---- 覆盖  
  58.   
  59.     // f()函数是virtual,pb又是父指针,他指向派生类,多态的体现  
  60.     // Derived::f(float) 3.14  
  61.     pb->f(3.14f);  
  62.   
  63.     // pd是派生类指针,所以他肯定是调用自己的函数  
  64.     // Derived::f(float) 3.14  
  65.     pd->f(3.14f); //  
  66.   
  67.   
  68.     // Bad 行为 ---- 隐藏与重载  
  69.   
  70.     // Base::g(float) 3.14  
  71.     pb->g(3.14f);  
  72.   
  73.     // g(float)非virtual函数,父类与子类中都有,这样就是隐藏  
  74.     // Derived::g(float) 3.14  
  75.     pd->g(3.14f);  
  76.   
  77.     // Derived::g(int) 4  
  78.     pd->g(4);  
  79.   
  80.     //特别注意,如果派生类中没有g(float)只有g(int)函数,那么pd->g(3.14f);  
  81.     //会输出 Derived::g(int) 3 是不是觉得很惊讶,自己可以试试,下面就展示出了  
  82.     //我刚才说的问题  
  83.   
  84.     // Bad 行为 ---- 隐藏  
  85.   
  86.     // Base::h(float) 3.14  
  87.     pb->h(3.14f);  
  88.   
  89.     // Derived::h(int) 3 惊讶!!!  
  90.     pd->h(3.14f);  
  91.   
  92.     return a.exec();  
  93. }  


输出结果:

 

 

其实这样来理解就比较容易搞懂了:   


1、虚函数的使用有特殊性,在使用的时候会查询指针所指对象内的虚函数表来确定具体应该调用的函数地址。因此调用虚函数的时候优先使用指针

所指对象的类函数,而不是其基类的类函数,如果找不到则才从其基类中找一个匹配的成员函数   



2、非虚成员函数的调用则是直接调用指针所指类对象的成员函数,而不会动态编译。 
  
  
   上面例子中pb是基类指针,pd是派生类指针,pd的所有函数调用都只是调用自己的函数,和多态性无关,所以pd的所有函数调用的结果都输出Derived::是完全正常的,

pb的函数调用如果有virtual则根据多态性调用派生类的,如果没有virtual则是正常的静态函数调用,还是调用基类的,所以有virtual的f函数调用输出Derived::,其它

两个没有virtual则还是输出Base::很正常啊,nothing surprise! 

记住“只有在通过基类指针或引用间接指向派生类子类型时多态性才会起作用”

 

http://blog.csdn.net/ac_huang/article/details/44487163

posted @ 2017-02-10 06:45  findumars  Views(395)  Comments(0Edit  收藏  举报