




版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
第C++的多態(tài)與虛函數(shù)你了解嗎目錄多態(tài)性虛函數(shù)總結
多態(tài)性
多態(tài)性是面向對象程序設計的關鍵技術之一,若程序設計語言不支持多態(tài)性,不能稱為面向對象的語言,利用多態(tài)性技術,可以調(diào)用同一個函數(shù)名的函數(shù),實現(xiàn)完全不同的功能
在C++中有兩種多態(tài)性:
編譯時的多態(tài)
通過函數(shù)的重載和運算符的重載來實現(xiàn)的
運行時的多態(tài)性
運行時的多態(tài)性是指在程序執(zhí)行前,無法根據(jù)函數(shù)名和參數(shù)來確定該調(diào)用哪一個函數(shù),必須在程序執(zhí)行過程中,根據(jù)執(zhí)行的具體情況來動態(tài)地確定;它是通過類繼承關系public和虛函數(shù)來實現(xiàn)的,目的也是建立一種通用的程序;通用性是程序追求的主要目標之一
通過引用或指針調(diào)用時,才可以達到運行時的多態(tài)
虛函數(shù)
虛函數(shù)是一個類的成員函數(shù),定義格式如下:
virtual返回類型函數(shù)名(參數(shù)表);
關鍵字virtual指明該成員函數(shù)為虛函數(shù),virtual僅用于類定義中,如虛函數(shù)在類外定義,不可加virtual
我們來看下面代碼
classAnimal
private:
stringname;
public:
Animal(conststringna):name(na)
public:
virtualvoideat(){}
virtualvoidwalk(){}
virtualvoidtail(){}
virtualvoidPrintInfo(){}
stringget_name()
returnname;
conststringget_name()const
returnname;
classDog:publicAnimal
private:
stringowner;
public:
Dog(conststringow,conststringna):Animal(na),owner(ow)
virtualvoideat()
cout"DogEat:bone"endl;
virtualvoidwalk()
cout"DogWalk:run"endl;
virtualvoidtail()
cout"DogTail:wangwang"endl;
virtualvoidPrintInfo()
cout"Dogowner"ownerendl;
cout"Dogname:"get_name()endl;
classCat:publicAnimal
private:
stringowner;
public:
Cat(conststringow,conststringna):Animal(na),owner(ow)
virtualvoideat()
cout"CatEat:fish"endl;
virtualvoidwalk()
cout"CatWalk:silent"endl;
virtualvoidtail()
cout"CatTail:miaomiao"endl;
virtualvoidPrintInfo()
cout"Catowner:"ownerendl;
cout"Catname:"get_name()endl;
//需要公有繼承公有繼承代表是一個的意思
//需要引用或指針調(diào)用
voidfun(Animalanimal)
animal.eat();//對象名稱.虛方法()
animal.walk();
animal.tail();
animal.PrintInfo();
intmain()
Dogdog("zyq","hashiqi");//conststringow="zyq"
Catcat("zyq","bosimao");
fun(dog);
fun(cat);
return0;
在這里我們可以看到,當我們調(diào)用fun()函數(shù)時,傳入dog對象則調(diào)用Dog的方法,傳入cat調(diào)用Cat方法;這就是所謂的運行時的多態(tài)
要想達到運行時的多態(tài)(晚綁定)需要滿足:
公有繼承有虛函數(shù)必須以指針或引用方式調(diào)用虛函數(shù)
若發(fā)生早綁定,則會調(diào)用Animal類型的方法
成員函數(shù)應盡可能的設置為虛函數(shù),但必須注意一下幾條:
1.派生類中定義虛函數(shù)必須與基類中的虛函數(shù)同名外,還必須同參數(shù)表,同返回類型;否則被認為是重載,而不是虛函數(shù)。如基類中返回基類指針,派生類中返回派生類指針是允許的,這是一個例外
2.只有類的成員函數(shù)才能說明為虛函數(shù),這是因為虛函數(shù)僅適用于有繼承關系的類對象
3.靜態(tài)成員函數(shù),是所有同一類對象公有,不受限于某個對象,不能作為虛函數(shù)(友元函數(shù)也不可以)
4.實現(xiàn)動態(tài)多態(tài)性時,必須使用基類類型的指針變量或引用,使該指針指向該基類的不同派生類的對象,并通過該指針指向虛函數(shù),才能實現(xiàn)動態(tài)的多態(tài)性
5.內(nèi)聯(lián)函數(shù)每個對象一個拷貝,無映射關系,不能作為虛函數(shù)
6.析構函數(shù)可定義為虛函數(shù),構造函數(shù)不可以定義為虛函數(shù),因為在調(diào)用構造函數(shù)時對象還沒有完成實例化;在基類中及其派生類中都動態(tài)分配的內(nèi)存空間時,必須把析構函數(shù)定義為虛函數(shù),實現(xiàn)撤銷對象時的多態(tài)性
7.函數(shù)執(zhí)行速度要稍慢一些,為了實現(xiàn)多態(tài)性,每一個派生類中均要保存相應虛函數(shù)的入口地址表,函數(shù)的調(diào)用機制也是間接實現(xiàn);所以多態(tài)性總要付出一定代價,但通用性是一個更高的目標
8.如果定義放在類外,virtual只能加在函數(shù)聲明前面,不能加載函數(shù)定義前面;正確的定義必須不包括virtual
虛函數(shù)是覆蓋,同名函數(shù)是隱藏
虛函數(shù)編譯過程
classObject
private:
intvalue;
public:
Object(intx=0):value(x)
virtualvoidadd()
cout"Object::add"endl;
virtualvoidfun()
cout"Object::fun"endl;
virtualvoidprint()const
cout"Object::print"endl;
classBase:publicObject
private:
intsum;
public:
Base(intx=0):Object(x+10),sum(x)
virtualvoidadd()
cout"Base::add"endl;
virtualvoidfun()
cout"Base::fun"endl;
virtualvoidprint()const
cout"Base::print"endl;
intmain()
此處虛函數(shù)表中進行的是同名覆蓋,而不像繼承關系中,同名成員進行隱藏,就近處理;虛函表僅有一份,存在數(shù)據(jù)區(qū)
在主函數(shù)創(chuàng)建對象
intmain()
Basebase(10);
Object*op=base;
可以看到base的大小為12字節(jié),因為其中基類對象Object,添加了虛表變?yōu)榱?字節(jié),且在構建過程,首先構建Object基類,此時虛表指針指向Object的虛表,而接著構建Base類的時候,會將虛表指針修改為指向Base的虛表
也就是,當有虛函數(shù)時,構造函數(shù)除了構建對象初始化對象的數(shù)據(jù)成員外,還會將虛表的地址給到虛表指針;同時這也是構造函數(shù)不可以作為虛函數(shù)的原因
intmain()
Basebase(10);
Object*op=NULL;
Objectobj(0);
op=base;
op-add();//指針或引用調(diào)動,則采用運行時多態(tài)
op-fun();
op-print();
obj=base;
obj.add();//對象直接調(diào)動,則采用編譯時多態(tài)
obj.fun();
obj.print();
也就是我們通過,對象名.方法的方式調(diào)用虛函數(shù),則通過編譯時多態(tài)的方式
運行時的多態(tài),是通過查詢虛表進行調(diào)用;下面通過匯編進一步查看
只有進行以指針調(diào)用或引用調(diào)用的時候才會對虛表進行查詢
三層繼承
classObject
private:
intvalue;
public:
Object(intx=0):value(x)
virtualvoidadd()
cout"Object::add"endl;
virtualvoidfun()
cout"Object::fun"endl;
virtualvoidprint()const
cout"Object::print"endl;
voidfn_a()
fun();
classBase:publicObject
private:
intsum;
public:
Base(intx=0):Object(x+10),sum(x)
virtualvoidadd()
cout"Base::add"endl;
virtualvoidfun()
cout"Base::fun"endl;
virtualvoidshow()
cout"Base::show"endl;
classTest:publicBase
private:
intnum;
public:
Test(intx=0):Base(x+10)
virtualvoidadd()
cout"Test::add"endl;
virtualvoidprint()const
cout"Test::print"endl;
virtualvoidshow()
cout"Test::show"endl;
我們可以看到虛函數(shù)表,當我們構建派生類,會復制基類的虛函數(shù)表,將虛表指針指向新的虛函數(shù)表,并且將同名的虛函數(shù)進行覆蓋
依舊使用上面代碼
/*
voidfn_a()
fu
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 術后早期康復
- 車工工藝與技能訓練(第二版)課件:車削工件的基準和定位基準的選擇
- 基于2025年目標的智慧物流配送體系建設資金申請項目風險管理
- 教育行業(yè)并購整合策略優(yōu)化路徑:2025年投資趨勢分析報告
- 人機工程學教學課件
- 新生兒窒息評估
- 術后疼痛護理讀書報告
- 有機磷農(nóng)藥中毒心理護理
- 智力低下康復
- 社區(qū)健康教育經(jīng)驗分享
- 大學生新材料項目創(chuàng)業(yè)計劃書
- 2025年蘇教版科學小學四年級下冊期末檢測題附答案(二)
- 小學生安全知識單選題100道及答案
- 廣州 國際健康產(chǎn)業(yè)城發(fā)展規(guī)劃方案
- 考研考博-英語-內(nèi)蒙古工業(yè)大學考試押題卷含答案詳解4
- 醫(yī)院二級庫管理制度(大全)
- 華為內(nèi)部控制PPT培訓課件
- 雨季監(jiān)理實施細則
- 分層審核檢查表LPA全套案例
- 三標一體文件編寫指南
- WC28E鏟板式搬運車使用維護說明書
評論
0/150
提交評論