重載與覆蓋的區別2

 
如果基類有某個函數的多個重載(overload)版本,而你在派生類中重寫(override)了基類中的一個或多個函數版本,或是在派生類中重新添加了新的函數版本(函數名相同,參數不同),則所有基類的重載版本都被屏蔽,在這裏我們稱之爲隱藏hide。所以,在一般情況下,你想在派生類中使用新的函數版本又想使用基類的函數版本時,你應該在派生類中重寫基類中的所有重載版本。你若是不想重寫基類的重載的函數版本,則你應該使用例4或例5方式,顯式聲明基類名字空間作用域。
 
事實上,C++編譯器認爲,相同函數名不同參數的函數之間根本沒有什麼關係,它們根本就是兩個毫不相關的函數。只是C++語言爲了模擬現實世界,爲了讓程序員更直觀的思維處理現實世界中的問題,才引入了重載和覆蓋的概念。重載是在相同名字空間作用域下,而覆蓋則是在不同的名字空間作用域下,比如基類和派生類即爲兩個不同的名字空間作用域。在繼承過程中,若發生派生類與基類函數同名問題時,便會發生基類函數的隱藏。當然,這裏討論的情況是基類函數前面沒有virtual 關鍵字。在有virtual 關鍵字關鍵字時的情形我們另做討論。
 
繼承類重寫了基類的某一函數版本,以產生自己功能的接口。此時C++編繹器認爲,你現在既然要使用派生類的自己重新改寫的接口,那我基類的接口就不提供給你了(當然你可以用顯式聲明名字空間作用域的方法,見[C++基礎]重載、覆蓋、多態與函數隱藏(1))。而不會理會你基類的接口是有重載特性的。若是你要在派生類裏繼續保持重載的特性,那你就自己再給出接口重載的特性吧。所以在派生類裏,只要函數名一樣,基類的函數版本就會被無情地屏蔽。在編繹器中,屏蔽是通過名字空間作用域實現的。
 
所以,在派生類中要保持基類的函數重載版本,就應該重寫所有基類的重載版本。重載只在當前類中有效,繼承會失去函數重載的特性。也就是說,要把基類的重載函數放在繼承的派生類裏,就必須重寫。
 
這裏“隱藏”是指派生類的函數屏蔽了與其同名的基類函數,具體規則我們也來做一小結:
       如果派生類的函數與基類的函數同名,但是參數不同。此時,若基類無virtual關鍵字,基類的函數將被隱藏。(注意別與重載混淆,雖然函數名相同參數不同應稱之爲重載,但這裏不能理解爲重載,因爲派生類和基類不在同一名字空間作用域內。這裏理解爲隱藏)
②  如果派生類的函數與基類的函數同名,但是參數不同。此時,若基類有virtual關鍵字,基類的函數將被隱式繼承到派生類的vtable。此時派生類vtable中的函數指向基類版本的函數地址。同時這個新的函數版本添加到派生類中,作爲派生類的重載版本。但在基類指針實現多態調用函數方法時,這個新的派生類函數版本將會被隱藏。
          如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數沒有virtual關鍵字。此時,基類的函數被隱藏。(注意別與覆蓋混淆,這裏理解爲隱藏)
          如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數有virtual關鍵字。此時,基類的函數不會被“隱藏”。(在這裏,你要理解爲覆蓋哦^_^)
 
插曲:基類函數前沒有virtual關鍵字時,我們要重寫更爲順口些,在有virtual關鍵字時,我們叫覆蓋更爲合理些,戒此,我也希望大家能夠更好的理解C++中一些微妙的東西。費話少說,我們舉例說明吧。
 
6
#include <iostream>
using namespace std;
 
class Base{
public:
       virtual void fun() { cout << "Base::fun()" << endl; }//overload
    virtual void fun(int i) { cout << "Base::fun(int i)" << endl; }//overload
};
 
class Derive : public Base{
public:
       void fun() { cout << "Derive::fun()" << endl; }//override
    void fun(int i) { cout << "Derive::fun(int i)" << endl; }//override
       void fun(int i,int j){ cout<< "Derive::fun(int i,int j)" <<endl;}//overload
};
 
int main()
{
 Base *pb = new Derive();
 pb->fun();
 pb->fun(1);
 //下面一句錯誤,故屏蔽掉
 //pb->fun(1,2);virtual函數不能進行overload,error C2661: 'fun' : no overloaded function takes 2 parameters
 
 cout << endl;
 Derive *pd = new Derive();
 pd->fun();
 pd->fun(1);
 pd->fun(1,2);//overload
 
 delete pb;
 delete pd;
 return 0;
}
/*
輸出結果
 
Derive::fun()
Derive::fun(int i)
 
Derive::fun()
Derive::fun(int i)
Derive::fun(int i,int j)
Press any key to continue
*/
 
7-1
#include <iostream>
using namespace std;
 
class Base{
public:
       virtual void fun(int i){ cout <<"Base::fun(int i)"<< endl; }
};
 
class Derive : public Base
{
};
 
int main()
{
       Base *pb = new Derive();
       pb->fun(1);//Base::fun(int i)
       delete pb;
       return 0;
}
7-2
 
#include <iostream>
using namespace std;
 
class Base{
public:
         virtual void fun(int i){ cout <<"Base::fun(int i)"<< endl; }
};
 
class Derive : public Base{
public:
    void fun(double d){ cout <<"Derive::fun(double d)"<< endl; } 
};
 
int main()
{
         Base *pb = new Derive();
         pb->fun(1);//Base::fun(int i)
              pb->fun((double)0.01);//Base::fun(int i)
         delete pb;
         return 0;
}
8-1
#include <iostream>
using namespace std;
 
class Base{
public:
       virtual void fun(int i){ cout <<"Base::fun(int i)"<< endl; }
};
 
class Derive : public Base{
public:
       void fun(int i){ cout <<"Derive::fun(int i)"<< endl; }
};
 
int main()
{
       Base *pb = new Derive();
       pb->fun(1);//Derive::fun(int i)
       delete pb;
       return 0;
}
8-2
#include <iostream>
using namespace std;
 
class Base{
public:
         virtual void fun(int i){ cout <<"Base::fun(int i)"<< endl; }
};
 
class Derive : public Base{
public:
       void fun(int i){ cout <<"Derive::fun(int i)"<< endl; }
         void fun(double d){ cout <<"Derive::fun(double d)"<< endl; }        
};
 
int main()
{
         Base *pb = new Derive();
         pb->fun(1);//Derive::fun(int i)
              pb->fun((double)0.01);//Derive::fun(int i)
         delete pb;
         return 0;
}
 
9
#include <iostream>
using namespace std;
 
class Base{
public:
         virtual void fun(int i){ cout <<"Base::fun(int i)"<< endl; }
 
};
class Derive : public Base{
public:
        void fun(int i){ cout <<"Derive::fun(int i)"<< endl; }
              void fun(char c){ cout <<"Derive::fun(char c)"<< endl; }  
              void fun(double d){ cout <<"Derive::fun(double d)"<< endl; }   
};
int main()
{
         Base *pb = new Derive();
         pb->fun(1);//Derive::fun(int i)
              pb->fun('a');//Derive::fun(int i)
              pb->fun((double)0.01);//Derive::fun(int i)
 
              Derive *pd =new Derive();
         pd->fun(1);//Derive::fun(int i)
         //overload
              pd->fun('a');//Derive::fun(char c)         
         //overload
              pd->fun(0.01);//Derive::fun(double d)         
 
         delete pb;
              delete pd;
         return 0;
}
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章