:虛函式必須是基類的非靜態成員函式,其訪問許可權可以是protected或public,在基類的類定義中定義虛函式的一般形式:
virtual 函式返回值型別 虛函式名(形參表)
虛函式的作用是實現動態聯編,也就是在程式的執行階段動態地選擇合適的成員函式,在定義了虛函式後,可以在基類的派生類中對虛函式重新定義,在派生類中重新定義的函式應與虛函式具有相同的形參個數和形參型別。以實現統一的介面,不同定義過程。如果在派生類中沒有對虛函式重新定義,則它繼承其基類的虛函式。
當程式發現虛函式名前的關鍵字virtual後,會自動將其作為動態聯編處理,即在程式執行時動態地選擇合適的成員函式。
動態聯編規定,只能通過指向基類的指標或基類物件的引用來呼叫虛函式,其格式:
指向基類的指標變數名->虛函式名(實參表)
或 基類物件的引用名. 虛函式名(實參表)
虛函式的例項:
#include
class cshape
void virtual display( void) ;
for( int i= 0; i< 4; i++)
pshape[i]->display( );
本程式執行結果:
cshape
cellipse
c********
csquare
所以,從以上程式分析,實現動態聯編需要三個條件:
1、 必須把動態聯編的行為定義為類的虛函式。
2、 類之間存在子型別關係,一般表現為乙個類從另乙個類公有派生而來。
3、 必須先使用基類指標指向子型別的物件,然後直接或者間接使用基類指標呼叫虛函式。
(1)非類的成員函式不能定義為虛函式,類的成員函式中靜態成員函式和建構函式也不能定義為虛函式,但可以將析構函式定義為虛函式。實際上,優秀的程式設計師常常把基類的析構函式定義為虛函式。因為,將基類的析構函式定義為虛函式後,當利用delete刪除乙個指向派生類定義的物件指標時,系統會呼叫相應的類的析構函式。而不將析構函式定義為虛函式時,只呼叫基類的析構函式。
(2)只需要在宣告函式的類體中使用關鍵字「virtual」將函式宣告為虛函式,而定義函式時不需要使用關鍵字「virtual」。
(3)當將基類中的某一成員函式宣告為虛函式後,派生類中的同名函式自動成為虛函式。
(4)如果宣告了某個成員函式為虛函式,則在該類中不能出現和這個成員函式同名並且返回值、引數個數、型別都相同的非虛函式。在以該類為基類的派生類中,也不能出現這種同名函式。
下面是對c++的虛函式這玩意兒的理解。
一, 什麼是虛函式(如果不知道虛函式為何物,但有急切的想知道,那你就應該從這裡開始)
簡單地說,那些被virtual關鍵字修飾的成員函式,就是虛函式。虛函式的作用,用專業術語來解釋就是實現多型性(polymorphism),多型性是將介面與實現進行分離;用形象的語言來解釋就是實現以共同的方法,但因個體差異而採用不同的策略。下面來看一段簡單的**
class a; //end//虛函式示例**2
int main(){
void (a::*fun)(); //定義乙個函式指標
a *p=new b;
fun=&a::fun;
(p->*fun)();
fun = &a::fun2;
(p->*fun)();
delete p;
system("pause");
你能估算出輸出結果嗎?如果你估算出的結果是a::fun和a::fun2,呵呵,恭喜恭喜,你中圈套了。其實真正的結果是b::fun和b::fun2,如果你想不通就接著往下看。給個提示,&a::fun和&a::fun2是真正獲得了虛函式的位址嗎?
首先我們回到第二部分,通過段實作**,得到乙個「通用」的獲得虛函式位址的方法
#include
using namespace std;
//將上面「虛函式示例**2」新增在這裡
void callvirtualfun(void* pthis,int index=0){
void (*funptr)(void*);
long lvptraddr;
memcpy(&lvptraddr,pthis,4);
memcpy(&funptr,reinterpret_cast(lvptraddr)+index,4);
funptr(pthis); //呼叫
int main(){
a* p=new b;
callvirtualfun(p); //呼叫虛函式p->fun()
callvirtualfun(p,1);//呼叫虛函式p->fun2()
system("pause");
現在我們擁有乙個「通用」的callvirtualfun方法。
這個通用方法和第三部分開始處的**有何聯絡呢?聯絡很大。由於a::fun()和a::fun2()是虛函式,所以&a::fun和&a::fun2獲得的不是函式的位址,而是一段間接獲得虛函式位址的一段**的位址,我們形象地把這段**看作那段callvirtualfun。編譯器在編譯時,會提供類似於callvirtualfun這樣的**,當你呼叫虛函式時,其實就是先呼叫的那段類似callvirtualfun的**,通過這段**,獲得虛函式位址後,最後呼叫虛函式,這樣就真正保證了多型性。同時大家都說虛函式的效率低,其原因就是,在呼叫虛函式之前,還呼叫了獲得虛函式位址的**。
最後的說明:本文的**可以用vc6和dev-c++4.9.8.0通過編譯,且執行無問題。其他的編譯器小弟不敢保證。其中,裡面的模擬方法只能看成模型,因為不同的編譯器的低層實現是不同的。例如this指標,dev-c++的gcc就是通過壓棧,當作引數傳遞,而vc的編譯器則通過取出位址儲存在ecx中。所以這些模擬方法不能當作具體實現
虛指標,虛函式,虛函式表,純虛函式
虛指標 虛繼承 在使用多重繼承時,如存在 class a 有m a變數 class a1 virtual public a,m a1 class a2 virtual public a m a2 class b public a1,public a2 m b 時 存在以下記憶體儲存順序 虛指標 指向...
虛函式 純虛函式
一 定義.純虛函式是在基類中宣告的虛函式,它在基類中沒有定義,但要求任何派生類都要定義自己的實現方法。在基類中實現純虛函式的方法是在函式原型後加 0 virtual void funtion1 0 二 引入原因 1 為了方便使用多型特性,我們常常需要在基類中定義虛函式。2 在很多情況下,基類本身生成...
虛函式 純虛函式
虛函式的作用是允許在派生類中重新定義與基類同名的函式,並且可以通過基類指標引用來訪問基類和派生類中的同名函式。include using namespace std class student student類成員函式的實現 宣告抽象基類shape class shape virtual float...