標籤:重載 函數調用 new nbsp 編程思想 rtu app 建立 ++
如果父類虛函數沒有被覆蓋,則這個虛函數是完全沒有意義的。
如有以下兩個類的繼承情況:
class Base{
public:
virtual void f(){ cout<<"Base::f()" <<endl; }
virtual void g(){ cout<<"Base::g()" <<endl; }
virtual void h(){ cout<<"Base::h()" <<endl; }
void m(){ cout << "Base::m()" << endl; }
};
class Derived:public Base{
public:
void f(){ cout << "Derived::f()"<< endl; }
void g(){ cout << "Derived::g()"<< endl; }
void m(){ cout << "Derived::m()" << endl; }
void n(){ cout << "Derived::n()"<< endl; }
};
第一種情況:我們使用虛函數一般是
Base*p=newDerived;
p->f(); // Derived::f()
p->g(); // Derived::g()
p->h(); // Base::h()
p->m(); // Base::m()
p->n();// 編譯報錯
這是因為:f和g都是虛函數,並且在Derived的對象中都已經將這個函數覆蓋了(注意要想覆蓋必須是除了函數體定義不同其他的完全相同,否則就不能覆蓋而視為不同的函數了);h是虛函數但是沒有被覆蓋;而n只是Derived類對象的成員函數而不是Base類的成員函數。
第一行代碼的意義就是:聲明一個對象,並把這個對象的指標強制轉換成一個Base類型的,我們知道在建立Derived類對象的時候,其中必然包含了Base基類中的所有內容,在進行指標強制轉換後,就只會在繼承的Base地區內尋找需要執行的對象或者需要操作的資料。根據上面所描述的,f和g被覆蓋了,所以調用的時候就會調用Derived的,h沒有被覆蓋所以調用Base的h,而n根本就不在這個地區內所以會編譯報錯:找不到這個成員。
第二種情況:
Derived*p=newDerived;
p->f(); // Derived::f()
p->g(); // Derived::g()
p->h(); // Base::h()
p->m(); // Derived::m()
p->n();// Derived::n()
這個時候並沒有把Derived類對象的指標做強制轉換,這個時候就會在Derived的地區內尋找資料和函數進行執行;這個時候實際上在Derived對象的體內,因為f和g被覆蓋了,所以只含有一個f和g而且是Derived的f和g;h沒有被覆蓋但是h是Base的h;總之對於虛函數的調用是通過查虛函數表來實現的。m在Base和Derived中都有定義但是不是虛函數,所以沒有覆蓋在這裡也不是重載,而是屬於兩個不同類的函數,在具體調用的時候首先是根據函數名稱即標識符來查看調用哪個類中的m函數,這個尋找過程是是又一定的名字尋找規則的,尤其是在多重繼承中體現更明顯,在C++編程思想第二卷P374中有具體尋找規則描述;確定類了之後再選擇函數具體的重載形式,比如如果在Base中m還有一個參數為int的重載形式,而在Derived中沒有,但是在調用的時候使用p->m(1)調用,在這個例子的情形下就會報錯,因為根據名稱尋找規則確定是使用Derived類中的m函數,但是這個類中沒有參數為int的重載形式,如果這在Derived中重載了這種形式則肯定沒有問題;同樣在Derived類中如果不定義m則也沒有問題,因為這個時候在名稱尋找的時候就會確定的是使用Base類中的m函數,而在Base類中恰好有m的int參數的重載形式,所以就不會報錯,只是這個時候就會調用Base類中的m函數了。
綜上兩種情況描述了目前我所見到的類繼承中的兩大類情形:一種就是虛函數的調用機制;另一種就是同名函數的尋找和調用機制。
虛函數調用(2)(轉載)