版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、第7章 多態(tài)性與虛函數 7.1 多態(tài)性的概念 7.2 靜態(tài)關聯與動態(tài)關聯 7.3 虛函數 7.4 純虛函數與抽象類 1高級教育 在C+程序設計中,多態(tài)性是指具有不同功 能的函數可以用同一個函數名,這樣就可以 用一個函數名調用不同內容的函數。 7.1 多態(tài)性的概念 2高級教育 多態(tài)的實現多態(tài)的實現 3高級教育 函數重載是多態(tài)性的一種簡單形式,它是指允許在相同的函數重載是多態(tài)性的一種簡單形式,它是指允許在相同的 作用域內,相同的函數名對應著不同的實現。作用域內,相同的函數名對應著不同的實現。 函數重載的條件是要求函數參數的類型或個數有所不同。函數重載的條件是要求函數參數的類型或個數有所不同。 對成
2、員函數的重載有以下三種表達方式:對成員函數的重載有以下三種表達方式: 1、在一個類中重載;、在一個類中重載; 2、在不同類中重載;、在不同類中重載; 3、基類的成員函數在派生類中重載。、基類的成員函數在派生類中重載。 4高級教育 具有相同名字的重載函數是在編譯時區(qū)分的,有以下三種區(qū)分具有相同名字的重載函數是在編譯時區(qū)分的,有以下三種區(qū)分 方法:方法: 1、根據參數的特征加以區(qū)別,例如:、根據參數的特征加以區(qū)別,例如: show(int, char); show (char*, float); 2、使用類作用域符、使用類作用域符“:”加以區(qū)分,例如:加以區(qū)分,例如: Circle:show();
3、 Point:show(); 3、根據類對象加以區(qū)分,例如:、根據類對象加以區(qū)分,例如: acirle.show()調用調用Circle:show() apoint.show()調用調用Point:show() 5高級教育 除了函數重載這種簡單形式之外,除了函數重載這種簡單形式之外,C+ 還提供了一還提供了一 種更為靈活的特征機制種更為靈活的特征機制虛函數。虛函數。 虛函數允許函數調用與函數體的聯系在運行時才給虛函數允許函數調用與函數體的聯系在運行時才給 出。出。當需要同一接口、多種實現時,這種功能顯得尤其當需要同一接口、多種實現時,這種功能顯得尤其 重要。重要。 在講述虛函數的概念之前,先介
4、紹子類型及靜態(tài)聯在講述虛函數的概念之前,先介紹子類型及靜態(tài)聯 編和動態(tài)聯編的相關內容。編和動態(tài)聯編的相關內容。 6高級教育 (動態(tài)多態(tài))要研究的問題是: 當一個基類被繼承為不同的派生類時,各 派生類可以使用與基類成員相同的成員名, 如果在運行時用同一個成員名調用類對象 的成員,會調用哪個對象的成員? 7高級教育 舉例舉例 根據類型適應性,在公有繼承方式下,指向基根據類型適應性,在公有繼承方式下,指向基 類和派生類的指針變量是相關的。如果類和派生類的指針變量是相關的。如果B 是基是基 類,類,D 是從是從B 公有派生出來的派生類,則在公有派生出來的派生類,則在 C+ 中,指向基類中,指向基類B
5、的指針的指針P 也可以指向派生也可以指向派生 類類D。 當當P 指向派生類指向派生類D 的對象時,利用指針的對象時,利用指針P 可以可以 訪問從基類訪問從基類B 繼承的成員,但派生類繼承的成員,但派生類D 自己定自己定 義的成員不能用義的成員不能用P 訪問訪問(除非用顯式類型轉換除非用顯式類型轉換)。 8高級教育 例如:下面是指向基類對象的指針指向派生類對象,而訪問從例如:下面是指向基類對象的指針指向派生類對象,而訪問從 基類繼承的成員的例子。基類繼承的成員的例子。 #include #include class B char name80; public: void put_name(cha
6、r *s) strcpy(name,s); void show_name() coutname“n”; ; 9高級教育 class D: public B char phone_num80; public: void put_phone(char *num) strcpy(phone_num,num); void show_phone() coutphone_numput_name(“Zhang Fang”); p= p-put_name(“Wang Ming”); /訪問從基類繼承的成員函數訪問從基類繼承的成員函數 Bobj.show_name(); Dobj.show_name(); dp
7、= dp-put_phone(“83768493”); /訪問自己的成員訪問自己的成員 dp-show_phone(); p-show_phone(); /error / 指向基類指針不能訪問派生類定指向基類指針不能訪問派生類定 義的成員義的成員 (D *)P)-show_phone(); /強行類型轉換強行類型轉換 11高級教育 Zhang Fang Wang Ming 83768493 83768493 注意:注意:希望用基類指針訪問其公有派生類的特定成員,必希望用基類指針訪問其公有派生類的特定成員,必 須將基類指針用顯式類型轉換為派生類指針。根據類型適應須將基類指針用顯式類型轉換為派生類
8、指針。根據類型適應 性的原則,一個指向基類的指針可用來指向以公有派生的任性的原則,一個指向基類的指針可用來指向以公有派生的任 何對象是何對象是C+ 實現運行時多態(tài)性的關鍵。實現運行時多態(tài)性的關鍵。 12高級教育 CommissionEmployee class CommissionEmployee public: CommissionEmployee( const string void setFirstName( const string / set first name string getFirstName() const; / return first name void setLas
9、tName( const string / set last name string getLastName() const; / return last name void setSocialSecurityNumber( const string / set SSN string getSocialSecurityNumber() const; / return SSN void setGrossSales( double ); / set gross sales amount double getGrossSales() const; / return gross sales amoun
10、t void setCommissionRate( double ); / set commission rate double getCommissionRate() const; / return commission rate double earnings() const; / calculate earnings void print() const; / print CommissionEmployee object private: string firstName; string lastName; string socialSecurityNumber; double gro
11、ssSales; / gross weekly sales double commissionRate; / commission percentage ; / end class CommissionEmployee 13高級教育 BasePlusCommissionEmployee class BasePlusCommissionEmployee : public CommissionEmployee public: BasePlusCommissionEmployee( const string void setBaseSalary( double ); / set base salar
12、y double getBaseSalary() const; / return base salary double earnings() const; / calculate earnings void print() const; / print BasePlusCommissionEmployee object private: double baseSalary; / base salary ; / end class BasePlusCommissionEmployee 14高級教育 派生類指針指向基類對象 int main() CommissionEmployee commiss
13、ionEmployee( Sue, Jones, 222-22-2222, 10000, .06 ); BasePlusCommissionEmployee *basePlusCommissionEmployeePtr = 0; / aim derived-class pointer at base-class object / Error: a CommissionEmployee is not a BasePlusCommissionEmployee basePlusCommissionEmployeePtr = return 0; / end main 15高級教育 基類對象指針指向派生
14、類對象 這種情況下,要訪問派生類的成員函數, 要做: /強制類型轉換 如: (BasePlusCommissionEmployee *) commissionEmployeePtr)-print(); 16高級教育 確定調用的具體對象的過程稱為關聯(binding)。 在這里是指把一個函數名與一個類對象捆綁在 一起,建立關聯。一般地說,關聯指把一個標 識符和一個存儲地址聯系起來。 7.2 靜態(tài)關聯與動態(tài)關聯 17高級教育 在編譯時即可確定其調用的函數,其過程稱 為靜態(tài)關聯(static binding),由于是在運行前 進行關聯的,故又稱為早期關聯(early binding)。 在運行階段把
15、虛函數和類對象“綁定”在一 起的,此過程稱為動態(tài)關聯(dynamic binding)。 這種多態(tài)性是動態(tài)的多態(tài)性,即運行階段的 多態(tài)性。由于動態(tài)關聯是在編譯以后的運行 階段進行的,因此也稱為滯后關聯(late binding)。 18高級教育 多態(tài)性分為兩類: 靜態(tài)多態(tài)性和動態(tài)多態(tài)性。 (1)靜態(tài)多態(tài): (例7-1) (在程序編譯時系統(tǒng)就能決定調用的是哪個函數), 因此靜態(tài)多態(tài)性又稱編譯時的多態(tài)性。靜態(tài)多 態(tài)是通過函數重載來實現的。 (2)動態(tài)多態(tài)(在例7-1基礎上加virtual) 是在程序運行過程中才動態(tài)地確定操作所針對 的對象。它又稱運行時的多態(tài)性。動態(tài)多態(tài)性 是通過虛函數(virtu
16、al function)實現的。 19高級教育 在類的繼承層次結構中,在不同的層次中可 以出現名字相同、參數個數和類型都相同而 功能不同的函數。編譯系統(tǒng)按照同名覆蓋的 原則決定調用的對象。 例7.2 基類與派生類中有同名函數。 7.3 虛函數 7.3.1 虛函數的作用 20高級教育 虛函數的作用: 允許在派生類中重新定義與基類同名的 函數,并且通過基類指針或引用來訪問基類 和派生類中的同名函數,實現動態(tài)多態(tài)的效 果。 21高級教育 虛函數是一種非靜態(tài)的成員函數,定義格式如下:虛函數是一種非靜態(tài)的成員函數,定義格式如下: virtual () / 其中,其中,virtual 是關鍵字。是關鍵字。
17、 如果某個類中的一個成員函數被說明為虛函數,該成員函如果某個類中的一個成員函數被說明為虛函數,該成員函 數可能在派生類中存在著不同的實現版本。數可能在派生類中存在著不同的實現版本。 由于存在有虛函數,編譯器將進行動態(tài)聯編,使調用虛函由于存在有虛函數,編譯器將進行動態(tài)聯編,使調用虛函 數的對象在運行時確定,以實現動態(tài)聯編的多態(tài)性。數的對象在運行時確定,以實現動態(tài)聯編的多態(tài)性。 22高級教育 例如:例如:使用虛函數將上例改為動態(tài)聯編的情況,將得到不同的使用虛函數將上例改為動態(tài)聯編的情況,將得到不同的 結果結果 #include class Base protected: int x; public
18、: Base(int a) x=a; virtual void print() cout“Base ”x“n”; ; 23高級教育 class First_d: public Base public: First_d(int a): Base(a) virtual void print() cout“First derivationn”x“n”; ; class Second_d: public Base public: Second_d(int a)=Base(a) virtual void print() cout“Second derivationn”xprint(); p= p-pri
19、nt(); p= p-print(); obj2.print(); obj3.print(); 運行結果:運行結果: Base 1 First derivation 2 Second derivation 3 First derivation 2 Second derivation 3 程序中,程序中,p-print();出現了三出現了三 次,由于次,由于p 指向的對象不同,每次指向的對象不同,每次 執(zhí)行了執(zhí)行了print() 的不同實現版本。的不同實現版本。 25高級教育 1、在基類中,將該函數說明為虛函數、在基類中,將該函數說明為虛函數(virtual); 2、定義基類的公有派生類;、定義
20、基類的公有派生類; 3、在基類的公有派生類中重載該虛函數;、在基類的公有派生類中重載該虛函數; 4、定義指向基類的指針變量,它指向基類的公有派生類的對、定義指向基類的指針變量,它指向基類的公有派生類的對 象。象。 重載虛函數不是一般的重載函數,它要求函數名、返回重載虛函數不是一般的重載函數,它要求函數名、返回 類型、參數個數、參數類型和順序完全相同。類型、參數個數、參數類型和順序完全相同。 由于對虛函數進行重載,因此,由于對虛函數進行重載,因此,在派生類中的虛函數前在派生類中的虛函數前 的的virtual關鍵字可以省略。關鍵字可以省略。 26高級教育 例如:例如:下面是下面是“單界面、多實現版
21、本單界面、多實現版本”概念的另一個程序例子概念的另一個程序例子 #include class figure protected: double x,y; public: void set_dim(double i; double j=0) x=i; y=j; virtual void show_area() cout“No area computation define ”; cout“for this class.n”; ; 27高級教育 class triangle: public figure public: void show_area() cout“Triangle with hig
22、h”; coutx“and base”y; cout“has an ares of”; coutx*0.5*y; ; class square: public figure public: void show_area() 28高級教育 cout“Square with dimension”; coutx“*”y; cout“has an area of”; coutx*y“n”; ; class circle: public figure public: void show_area() cout“Circle with radius”; coutx; cout“has an area of
23、”; coutset_dim(10.0,5.0); p-show_area(); Triangle with high 10 and 5 has an area of 25.0 Square with dimension 10*5 has an area of 50.0 Circle with radius 9 has an area of 254.34 p= p-show_area(); p= p-set_dim(9.0); p-show_area(); 30高級教育 虛函數的使用方法: (1) 在基類用virtual聲明成員函數為虛函數。這樣 就可以在派生類中重新定義此函數,為它賦予 新的
24、功能,并能方便地被調用。 注意事項: 在派生類中重新定義此函數,要求函 數名、函數類型、函數參數個數和類型全部與 基類的虛函數相同,并根據派生類的需要重新 定義函數體。 31高級教育 (2) 定義一個指向基類對象的指針變量或對象 的引用,并使它指向同一類族中需要調用該 函數的對象。(即使用賦值兼容規(guī)則) (3) 通過該指針變量或對象的引用調用此虛函 數。 示例:指針調用,引用調用 32高級教育 使用虛函數時,有幾點要注意: (1)(1)只能用只能用virtualvirtual聲明類的成員函數,使它成為虛聲明類的成員函數,使它成為虛 函數函數,而不能將類外的普通函數聲明為虛函數。因,而不能將類外
25、的普通函數聲明為虛函數。因 為虛函數的作用是允許在派生類中對基類的虛函數為虛函數的作用是允許在派生類中對基類的虛函數 重新定義。重新定義。顯然,它只能用于類的繼承層次結構中顯然,它只能用于類的繼承層次結構中。 (2) (2) 一個成員函數被聲明為虛函數后,在同一類族一個成員函數被聲明為虛函數后,在同一類族 中的類就不能再定義一個中的類就不能再定義一個非非virtualvirtual的但與該虛函的但與該虛函 數具有相同的參數數具有相同的參數( (包括個數和類型包括個數和類型) )和函數返回值和函數返回值 類型的同名函數。類型的同名函數。 (3)(3)構造函數不能聲明為虛函數構造函數不能聲明為虛函
26、數。這是因為在執(zhí)行。這是因為在執(zhí)行 構造函數時類對象還未完成建立過程,當然談不上構造函數時類對象還未完成建立過程,當然談不上 函數與類對象的綁定。函數與類對象的綁定。 33高級教育 (1) 首先看成員函數所在的類是否會作為基類。 然后看成員函數在類的繼承后有無可能被更 改功能,如果希望更改其功能的,一般應該 將它聲明為虛函數。 如果成員函數在類被繼承后功能不需修改, 或派生類用不到該函數,則不要把它聲明為 虛函數。不要僅僅考慮到要作為基類而把類 中的所有成員函數都聲明為虛函數。 7.3.2 在什么情況下應當聲明虛函數 34高級教育 (2) 應考慮對成員函數的調用是通過對象名還 是通過基類指針或
27、引用去訪問,如果是通過 基類指針或引用去訪問的,則應當聲明為虛 函數。 (3) 有時,在定義虛函數時,并不定義其函數 體,即函數體是空的。它的作用只是定義了 一個虛函數名,具體功能留給派生類去添加。 35高級教育 注意事項: 使用虛函數,系統(tǒng)要有一定的空間開銷。 當一個類帶有虛函數時,編譯系統(tǒng)會為該類 構造一個虛函數表(virtual function table,簡 稱vtable),它是一個指針數組,存放每個虛 函數的入口地址。系統(tǒng)在進行動態(tài)關聯時的 時間開銷是很少的,因此,多態(tài)性是高效的。 36高級教育 純虛函數是一種特殊的虛函數,是一種沒有具純虛函數是一種特殊的虛函數,是一種沒有具 體
28、實現的虛函數,其定義格式如下:體實現的虛函數,其定義格式如下: 37高級教育 Class D1 also is an abstract class. 例如:例如:下面舉一個計算某些幾何圖形的面積下面舉一個計算某些幾何圖形的面積 之和的例子,以說明純虛函數及抽象類的之和的例子,以說明純虛函數及抽象類的 應用。例中各類之間的關系如下:應用。例中各類之間的關系如下: Shape TriangleRectangleCircleTrapezoidSquare Application MyProgram 38高級教育 # include Class Shape Public: virtual double
29、 Area() const=0; ; class Circle: public Shape public: Circle(double r) R=r; double Area() const return 3.14*R*R; private: double R; ; 39高級教育 class Trapezoid: public Shape public: Trapezoid(double t, double b, double h) T=t; B=b; H=h; double Area() const return 0.5*(T+B)*H; private: double T,B,H; ; c
30、lass Square: public Shape public: Square(double s) S=s; double Area() const return S*S; private: double S; ; 40高級教育 class Application public: double Compute(Shape *s ,int n) const ; double Application:Compute(Shape *s , int n) const double sum=0; for(int i=0; iArea(); return sum; 41高級教育 class MyProg
31、ram : public Application MyProgram(); Myprogram(); double Run(); private: Shape *S; ; MyProgram:MyProgram() S=new Shape *5; S0=new Triangle(3.0,5.0); S1=new Rectangle(5.0,8.0); S2=new Circle(8.5); S3=new Trapezoid(12.0,8.0,6.0); S4=new Square(6.8); 42高級教育 MyProgram:MyProgram() for(int i=0; i5; i+) d
32、elete Si; /for(int i=0; i5; i+) delete S ; double MyProgram:Run() double sum=compute(S,5); return sum; void main() MyProgram M; cout“Areas sum=”M.Run()endl; 輸出結果:輸出結果: Areas sum=380.713 43高級教育 1、該程序定義了、該程序定義了8個類,其關系如前圖所示;個類,其關系如前圖所示; 2、類、類Shape 定義為抽象類,相當于定義為抽象類,相當于Triangle 等等5個類的個類的 根,根,Shape 類中定義純虛
33、函數類中定義純虛函數Area(),在它的,在它的5個派生類個派生類 中定義其具體實現;中定義其具體實現; 3、在類、在類Application 中定義了計算面積和的函數中定義了計算面積和的函數 Compute(),在其派生類,在其派生類MyProgram 中定義中定義Run()函數,函數, 以調用計算面積和函數以調用計算面積和函數Compute()。 44高級教育 該例說明的設計特點:類庫和應用程序設計分開。該例說明的設計特點:類庫和應用程序設計分開。 幾何圖形面積類庫幾何圖形面積類庫建立抽象類,作為繼承的層次結構中的公建立抽象類,作為繼承的層次結構中的公 共根,方便圖形的增添或減少。共根,方
34、便圖形的增添或減少。 應用程序應用程序取決于用戶需求,只需修改取決于用戶需求,只需修改MyProgram 類的構造類的構造 函數中的參數。函數中的參數。 45高級教育 抽象類包含一個或多個純抽象類包含一個或多個純virtual函數,這些函數必須要在具體函數,這些函數必須要在具體 的派生類派生。的派生類派生。 抽象類不能實例化對象。抽象類不能實例化對象。 class character_device public: virtual int open(int opt)=0; virtual int close(int opt)=0; virtual int read(char *p, int n)=0; virtual int write(const char *p, int n)=0; virtual int ioct1(int )=0; virtual character_device() /virtual destructor ; 抽象類 46高級教育 有時在基類中將某一成員函數定為虛函數, 并不是基類本身的要求,而是考慮到派生類 的需要,在基類中預留了一
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度生物醫(yī)藥領域基因編輯技術研發(fā)合同3篇
- 2025年度物業(yè)服務合同管理與維護條款研究6篇
- 二零二五年度戶外廣告牌安全檢測與維護合同3篇
- 二零二五年度弱電工程環(huán)境保護合同2篇
- 2025年度旅行社旅游紀念品開發(fā)承包合同3篇
- 二零二五年度有限合伙基金代持協議書3篇
- 二零二五年度學生宿舍租賃協議范文2篇
- 海南醫(yī)學院《中醫(yī)文獻檢索》2023-2024學年第一學期期末試卷
- 軸套編程課程設計
- 軸流式葉輪課程設計
- 2024年海南發(fā)展控股有限公司招聘筆試參考題庫含答案解析
- 內科常見疾病中醫(yī)診療規(guī)范診療指南2023版
- 《動物營養(yǎng)與飼料》課件
- 附表四計劃開、竣工日期和施工進度網絡圖
- 2023服裝跟單工作總結
- 兒童哮喘控制測試(C-ACT)
- 福建泉州惠安縣2023-2024學年數學四年級第一學期期末質量跟蹤監(jiān)視試題含答案
- DL5168-2023年110KV-750KV架空輸電線路施工質量檢驗及評定規(guī)程
- 門診發(fā)生火災應急預案演練建議5篇,門診發(fā)生火災的應急預案
- 醫(yī)療廢物轉運工作制度
- 新編建筑施工扣件式鋼管腳手架安全技術規(guī)范
評論
0/150
提交評論