




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
C++大學(xué)基礎(chǔ)教程第11章多態(tài)性
北京科技大學(xué)信息基礎(chǔ)科學(xué)系2023/12/221北京科技大學(xué)多態(tài)性(Polymorphism)是面向?qū)ο蟪绦蛟O(shè)計的主要特征之一。多態(tài)性對于軟件功能的擴展和軟件重用都有重要的作用。是學(xué)習(xí)面向?qū)ο蟪绦蛟O(shè)計必須要掌握的主要內(nèi)容之一。2第十一章多態(tài)性11.1多態(tài)性的概念11.2繼承中的靜態(tài)聯(lián)編11.3虛函數(shù)和運行時的多態(tài)11.4純虛函數(shù)和抽象類11.5繼承和派生的應(yīng)用11.6模板
311.1多態(tài)性的概念
2023/12/224北京科技大學(xué)11.1.1面向?qū)ο蟪绦蛟O(shè)計中多態(tài)的表現(xiàn)
總的來說,不同對象對于相同的消息有不同的響應(yīng),就是面向?qū)ο蟪绦蛟O(shè)計中的多態(tài)性。具體在程序中,多態(tài)性有兩種表現(xiàn)的方式:同一個對象調(diào)用名字相同、但是參數(shù)不同的函數(shù),表現(xiàn)出不同的行為。在同一個類中定義的重載函數(shù)的調(diào)用,屬于這種情況。不同的對象調(diào)用名字和參數(shù)都相同的函數(shù),表現(xiàn)出不同的行為。在派生類的應(yīng)用中,經(jīng)常會看到這樣的調(diào)用。511.1.1面向?qū)ο蟪绦蛟O(shè)計中多態(tài)的表現(xiàn)面向?qū)ο蟪绦蛟O(shè)計中多態(tài)性表現(xiàn)為以下幾種形式:重載多態(tài):通過調(diào)用相同名字的函數(shù),表現(xiàn)出不同的行為。運算符重載也是一種重載多態(tài)。
運行多態(tài):通過基類的指針,調(diào)用不同派生類的同名函數(shù),表現(xiàn)出不同的行為。許多面向?qū)ο蟪绦蛟O(shè)計的書籍中所說的多態(tài)性,就是這種多態(tài)。模板多態(tài),也稱為參數(shù)多態(tài):611.1.2多態(tài)的實現(xiàn):聯(lián)編
一個具有多態(tài)性的程序語句,在執(zhí)行的時候,必須確定究竟是調(diào)用哪一個函數(shù)。也就是說,在執(zhí)行的時候調(diào)用哪個函數(shù)是唯一地確定的。確定具有多態(tài)性的語句究竟調(diào)用哪個函數(shù)的過程稱為聯(lián)編(Binding),有的資料也翻譯成“綁定”。711.1.2多態(tài)的實現(xiàn):聯(lián)編聯(lián)編有兩種方式:靜態(tài)聯(lián)編和動態(tài)聯(lián)編。在源程序編譯的時候就能確定具有多態(tài)性的語句調(diào)用哪個函數(shù),稱為靜態(tài)聯(lián)編。對于重載函數(shù)的調(diào)用就是在編譯的時候確定具體調(diào)用哪個函數(shù),所以是屬于靜態(tài)聯(lián)編。811.1.2多態(tài)的實現(xiàn):聯(lián)編動態(tài)聯(lián)編則是必須在程序運行時,才能夠確定具有多態(tài)性的語句究竟調(diào)用哪個函數(shù)。用動態(tài)聯(lián)編實現(xiàn)的多態(tài),也稱為運行時的多態(tài)。911.2繼承中的靜態(tài)聯(lián)編
2023/12/2210北京科技大學(xué)11.2.1派生類對象調(diào)用同名函數(shù)
在派生類中可以定義和基類中同名的成員函數(shù)。這是對基類進行改造,為派生類增加新的行為的一種常用的方法。通過不同的派生類的對象,調(diào)用這些同名的成員函數(shù),實現(xiàn)不同的操作,也是多態(tài)性的一種表現(xiàn)。在程序編譯的時候,就可以確定派生類對象具體調(diào)用哪個同名的成員函數(shù)。這是通過靜態(tài)聯(lián)編實現(xiàn)的多態(tài)。11
例11.1定義Circle類和Rectangle類為Shape類的派生類,通過Circle類和Rectangle類的對象調(diào)用重載函數(shù)getArea()顯示對象的面積。
//例11.1:shape.h#ifndefSHAPE_H#defineSHAPE_H
classShape{ public: doublegetArea()const; voidprint()const; }; //Shape類定義結(jié)束12
classCircle:publicShape{ public: Circle(int=0,int=0,double=0.0); doublegetArea()const; //返回面積
voidprint()const; //輸出Circle類對象private:
intx,y; //圓心座標(biāo)
doubleradius; //圓半徑}; //派生類Circle定義結(jié)束classRectangle:publicShape{ public: Rectangle(int=0,int=0); //構(gòu)造函數(shù)
doublegetArea()const; //返回面積
voidprint()const; //輸出Rectangle類對象private:
inta,b; //矩形的長和寬}; //派生類Rectangle定義結(jié)束#endif13
//例11.1:shape.cpp#include<iostream>usingnamespacestd;#include"shape.h"
doubleShape::getArea()const{
cout<<"基類的getArea函數(shù),面積是";return0.0;} //Shape類getArea函數(shù)的定義voidShape::print()const{
cout<<"BaseclassObject"<<endl;} //Shape類print函數(shù)定義基類成員函數(shù)的定義14
Circle::Circle(int
xValue,int
yValue,doubleradiusValue){ x=xValue;y=yValue; radius=radiusValue;} //Circle類構(gòu)造函數(shù)doubleCircle::getArea()const{
cout<<"Circle類的getArea函數(shù),面積是";
return3.14159*radius*radius;} //Circle類getArea函數(shù)定義voidCircle::print()const{
cout<<"centeris";
cout<<"x="<<x<<"y="<<y;
cout<<";radiusis"<<radius<<endl;} //Circle類print函數(shù)定義Circle類成員函數(shù)的定義15
Rectangle::Rectangle(int
aValue,int
bValue){ a=aValue;b=bValue;} //Rectangle類構(gòu)造函數(shù)doubleRectangle::getArea()const{
cout<<"Rectangle類的getArea函數(shù),面積是";
returna*b;} //Rectangle類getArea函數(shù)定義voidRectangle::print()const{
cout<<"hightis"<<a;
cout<<"widthis"<<b<<endl;} //Rectangle類print函數(shù)定義
Rectangle類成員函數(shù)的定義16
//例11.1:11_1.cpp#include<iostream>usingstd::cout;usingstd::endl;
#include"shape.h" //包含頭文件voidmain(){Circlecircle(22,8,3.5);//創(chuàng)建Circle類對象
Rectanglerectangle(10,10);//創(chuàng)建Rectangle類對象
cout<<"調(diào)用的是";
cout<<circle.getArea()<<endl;//靜態(tài)聯(lián)編
cout<<"調(diào)用的是";
cout<<rectangle.getArea()<<endl;//靜態(tài)聯(lián)編} 例11.1的主函數(shù)調(diào)用的是Circle類的getarea函數(shù),面積是38.4845
調(diào)用的是Ractangle類的getarea函數(shù),面積是100
1711.2.1派生類對象調(diào)用同名函數(shù)對于派生類對象調(diào)用成員函數(shù),可以有以下的結(jié)論:
派生類對象可以直接調(diào)用本類中與基類成員函數(shù)同名的函數(shù),不存在二義性;在編譯時就能確定對象將調(diào)用哪個函數(shù),屬于靜態(tài)聯(lián)編,不屬于運行時的多態(tài)。
1811.2.2通過基類指針調(diào)用同名函數(shù)
從繼承的角度來看,派生類對象是基類對象的一個具體的特例?;蛘哒f,派生類對象是某一種特定類型的基類對象。例如,Circle類是Shape類的公有繼承,“圓”是“圖形”的一種特例?;蛘哒f,圓是一種特定的圖形,具有圖形的基本特征。但是,這種關(guān)系不是可逆的。不可以說基類的對象具有派生類對象的特征,基類對象也不是派生類對象的一個特例。1911.2.2通過基類指針調(diào)用同名函數(shù)
在關(guān)于基類對象和派生類對象的操作上,可以允許以下的操作:派生類對象可以賦值給基類對象;派生類對象的地址可以賦值給基類對象的指針?;蛘哒f,可以用派生類對象的地址初始化基類對象的指針;可以將基類對象的引用,定義為派生類對象的別名,或者說,用派生類對象初始化基類的引用。通過派生類對象的地址初始化的基類對象的指針,可以訪問基類的公有成員,也可以訪問和基類成員函數(shù)同名的函數(shù)。2011.2.2通過基類指針調(diào)用同名函數(shù)
以下這些操作是不可以進行的:不可以將基類對象賦值給派生類對象;不可以用基類對象的地址初始化派生類對象的指針;不可以將派生類對象的引用定義為基類對象的別名;不可以通過用派生類對象初始化的基類對象的指針,訪問派生類新增加的和基類公有成員不重名的公有成員。21
例11.2在例11.1所定義的類的基礎(chǔ)上,觀察通過派生類對象地址初始化的基類對象的指針訪問getArea函數(shù)的結(jié)果。
#include<iostream>usingnamespacestd;#include"shape.h" voidmain(){Shape*shape_ptr;
Circlecircle(22,8,3.5);
Rectanglerectangle(10,10);
shape_ptr=&circle;
cout<<shape_ptr->getArea()<<endl;//靜態(tài)聯(lián)編
shape_ptr=&rectangle;
cout<<shape_ptr->getArea()<<endl;//靜態(tài)聯(lián)編} circle對象初始化shape_ptr指針訪問的getArea函數(shù)是基類的getArea函數(shù),面積是0rectangle對象初始化shape_ptr指針訪問的getArea函數(shù)是基類的getArea函數(shù),面積是02211.2.2通過基類指針調(diào)用同名函數(shù)
程序運行結(jié)果表明:確實可以用派生類對象的地址初始化基類對象的指針;通過用派生類對象地址初始化的基類對象指針,只能調(diào)用基類的公有成員函數(shù)。在以上例子中,就是調(diào)用基類的getArea函數(shù),而不是派生類的getArea函數(shù)。這種調(diào)用關(guān)系的確定,也是在編譯的過程中完成的,屬于靜態(tài)聯(lián)編,而不屬于運行時的多態(tài)。
2311.3虛函數(shù)和運行時的多態(tài)
2023/12/2224北京科技大學(xué)11.3虛函數(shù)和運行時的多態(tài)通過指向基類的指針訪問基類和派生類的同名函數(shù),是實現(xiàn)運行時的多態(tài)的必要條件,但不是全部條件。除此以外,還必須將基類中的同名函數(shù)定義為虛函數(shù)。2511.3.1虛函數(shù)虛函數(shù)可以在類的定義中聲明函數(shù)原型的時候來說明,格式如下:virtual<返回值類型>函數(shù)名(參數(shù)表);在函數(shù)原型中聲明函數(shù)是虛函數(shù)后,具體定義這個函數(shù)時就不需要再說明它是虛函數(shù)了。如果在基類中直接定義同名函數(shù),定義虛函數(shù)的格式是:virtual<返回值類型>函數(shù)名(參數(shù)表){<函數(shù)體>}2611.3.1虛函數(shù)基類中的同名函數(shù)聲明或定義為虛函數(shù)后,派生類的同名函數(shù)無論是不是用virtual來說明,都將自動地成為虛函數(shù)。從程序可讀性考慮,一般都會在這些函數(shù)的聲明或定義時,用virtual來加以說明。只要對例11.2中的頭文件稍加修改,也就是將基類和派生類中的getArea函數(shù)都聲明為虛函數(shù),再重新編譯和運行程序,就可以得到運行時的多態(tài)的效果。27
例11.3將例11.2進行修改,使得程序具有運行時的多態(tài)的效果。
//例11.3:shape1.h#ifndefSHAPE_H#defineSHAPE_H
classShape{ public:
virtualdoublegetArea()const; voidprint()const; }; //Shape類定義結(jié)束28
classCircle:publicShape{ public: Circle(int=0,int=0,double=0.0);
virtualdoublegetArea()const; //返回面積
voidprint()const; //輸出Circle類對象tprivate:
intx,y; //圓心座標(biāo)
doubleradius; //圓半徑}; //派生類Circle定義結(jié)束classRectangle:publicShape{ public: Rectangle(int=0,int=0); //構(gòu)造函數(shù)
virtual
doublegetArea()const; //返回面積
voidprint()const; //輸出Rectangle類對象private:
inta,b; //矩形的長和寬}; //派生類Rectangle定義結(jié)束#endif29
例11.2在例11.1所定義的類的基礎(chǔ)上,觀察通過派生類對象地址初始化的基類對象的指針訪問getArea函數(shù)的結(jié)果。
#include<iostream>usingnamespacestd;#include"shape1.h" voidmain(){Shape*shape_ptr;
Circlecircle(22,8,3.5);
Rectanglerectangle(10,10);
shape_ptr=&circle;
cout<<shape_ptr->getArea()<<endl;//動態(tài)聯(lián)編
shape_ptr=&rectangle;
cout<<shape_ptr->getArea()<<endl;//動態(tài)聯(lián)編} circle對象初始化shape_ptr指針訪問的getArea函數(shù)是Circle類的getArea函數(shù),面積是38.4845rectangle對象初始化shape_ptr指針訪問的getArea函數(shù)是Rectangle類的getArea函數(shù),面積是1003011.3.1虛函數(shù)這個結(jié)果和例11.2的結(jié)果大不相同。同樣的shape_ptr->getArea()函數(shù)調(diào)用,當(dāng)shape_ptr指針中是Circle類對象地址時,訪問的是Circle類的getArea函數(shù)。而shape_ptr指針中是Rectangle類對象的地址時,訪問的是Rectangle類的getArea函數(shù)。這種方式的函數(shù)調(diào)用,在編譯的時候是不能確定具體調(diào)用哪個函數(shù)的。只有程序運行后,才能知道指針shape_ptr中存放的是什么對象的地址,然后再決定調(diào)用哪個派生類的函數(shù)。是一種運行時決定的多態(tài)性。3111.3.1虛函數(shù)要實現(xiàn)運行時的多態(tài),需要以下條件:必須通過指向基類對象的指針訪問和基類成員函數(shù)同名的派生類成員函數(shù);或者用派生類對象初始化的基類對象的引用訪問和基類成員函數(shù)同名的派生類成員函數(shù);派生類的繼承方式必須是公有繼承;基類中的同名成員函數(shù)必須定義為虛函數(shù)。3211.3.2虛函數(shù)的使用虛函數(shù)必須正確的定義和使用。否則,即使在函數(shù)原型前加了virtual的說明,也可能得不到運行時多態(tài)的特性。必須首先在基類中聲明虛函數(shù)。在多級繼承的情況下,也可以不在最高層的基類中聲明虛函數(shù)。例如在第二層定義的虛函數(shù),可以和第三層的虛函數(shù)形成動態(tài)聯(lián)編。但是,一般都是在最高層的基類中首先聲明虛函數(shù)。3311.3.2虛函數(shù)的使用基類和派生類的同名函數(shù),必須函數(shù)名、返回值、參數(shù)表全部相同,才能作為虛函數(shù)來使用。否則,即使函數(shù)用virtual來說明,也不具有虛函數(shù)的行為。靜態(tài)成員函數(shù)不可以聲明為虛函數(shù)。構(gòu)造函數(shù)也不可以聲明為虛函數(shù)。析構(gòu)函數(shù)可以聲明為虛函數(shù),即可以定義虛析構(gòu)函數(shù)。34
例11.4虛函數(shù)的正確使用。分析以下程序,編譯時哪個語句會出現(xiàn)錯誤?為什么?將有錯誤的語句屏蔽掉以后,程序運行結(jié)果如何?其中哪些調(diào)用是靜態(tài)聯(lián)編,哪些是動態(tài)聯(lián)編?
#include<iostream.h>classBB{public:virtualvoidvf1(){cout<<"BB::vf1被調(diào)用\n";}virtualvoidvf2(){cout<<"BB::vf2被調(diào)用\n";}voidf(){cout<<"BB::f被調(diào)用\n";}};classDD:publicBB{public:virtualvoidvf1(){cout<<"DD::vf1被調(diào)用\n";}voidvf2(inti){cout<<i<<endl;}voidf(){cout<<"DD::f\n被調(diào)用";}};35
voidmain(){DDd;BB*bp=&d;
bp->vf1();
bp->vf2();
bp->vf2(10);
bp->f();}將這個語句注釋掉后,運行結(jié)果將顯示:
DD::vf1被調(diào)用BB::vf2被調(diào)用BB::f被調(diào)用函數(shù)調(diào)用bp->vf2(10);是錯誤的。因為派生類的vf2函數(shù)和基類的vf2函數(shù)的參數(shù)不同,派生類的vf2就不是虛函數(shù)。
其中bp->vf1()調(diào)用是動態(tài)聯(lián)編。bp->vf2()是靜態(tài)聯(lián)編。bp->f()也是靜態(tài)聯(lián)編。
3611.3.3虛析構(gòu)函數(shù)如果用動態(tài)創(chuàng)建的派生類對象的地址初始化基類的指針,創(chuàng)建的過程不會有問題:仍然是先調(diào)用基類構(gòu)造函數(shù),再執(zhí)行派生類構(gòu)造函數(shù)。但是,在用delete運算符刪除這個指針的時候,由于指針是指向基類的,通過靜態(tài)聯(lián)編,只會調(diào)用基類的析構(gòu)函數(shù),釋放基類成員所占用的空間。而派生類成員所占用的空間將不會被釋放。37
#include<iostream>usingnamespacestd;classShape{ public: Shape(){cout<<"Shape類構(gòu)造函數(shù)被調(diào)用\n";} ~Shape(){cout<<"Shape類析構(gòu)函數(shù)被調(diào)用\n";} }; classCircle:publicShape{ public: Circle(int
xx=0,int
yy=0,doublerr=0.0) {x=xx;y=yy;radius=rr;
cout<<"Circle類構(gòu)造函數(shù)被調(diào)用\n";} ~Circle(){cout<<"Circle類析構(gòu)函數(shù)被調(diào)用\n";}private:
intx,y;
doubleradius; }; voidmain(){Shape*shape_ptr;shape_ptr=newCircle(3,4,5);deleteshape_ptr;}例11.5定義簡單的Shape類和Circle類,觀察基類指針的創(chuàng)建和釋放時如何調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)。程序運行后在屏幕上顯示:Shape類構(gòu)造函數(shù)被調(diào)用Circle類構(gòu)造函數(shù)被調(diào)用Shape類析構(gòu)函數(shù)被調(diào)用3811.3.3虛析構(gòu)函數(shù)為了解決派生類對象釋放不徹底的問題,必須將基類的析構(gòu)函數(shù)定義為虛析構(gòu)函數(shù)。格式是在析構(gòu)函數(shù)的名字前添加virtual關(guān)鍵字。函數(shù)原型如下:
virtual~Shape();此時,無論派生類析構(gòu)函數(shù)是不是用virtual來說明,也都是虛析構(gòu)函數(shù)。再用deleteshape_ptr來釋放基類指針時,就會通過動態(tài)聯(lián)編調(diào)用派生類的析構(gòu)函數(shù)。3911.3.3虛析構(gòu)函數(shù)將例11.5程序中的~Shape析構(gòu)函數(shù)作以上修改后,運行的結(jié)果將是:
Shape類構(gòu)造函數(shù)被調(diào)用
Circle類構(gòu)造函數(shù)被調(diào)用
Circle類析構(gòu)函數(shù)被調(diào)用
Shape類析構(gòu)函數(shù)被調(diào)用4011.4純虛函數(shù)和抽象類
4111.4純虛函數(shù)和抽象類在前面的幾個例子中,基類Shape本身并不是一個具體的“形狀”的抽象,而是各種實際的“形狀”的抽象。在C++中,對于那些在基類中不需要定義具體的行為的函數(shù),可以定義為純虛函數(shù)。
對于那些只是反映一類事物公共特
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度股東致行動協(xié)議:董事會席位調(diào)整與決策權(quán)分配
- 二零二五年度汽車充電樁場地租賃及維護服務(wù)合同
- 旅游景區(qū)服務(wù)質(zhì)量提升策略手冊
- 汽車配件銷售及售后支持協(xié)議
- 企業(yè)級軟件系統(tǒng)開發(fā)合作協(xié)議
- 水滸傳經(jīng)典人物宋江征文
- 租賃房屋補充協(xié)議
- 關(guān)于提高工作效率的研討會紀(jì)要
- 文化創(chuàng)意產(chǎn)業(yè)發(fā)展規(guī)劃策略
- 融資租賃資產(chǎn)轉(zhuǎn)讓協(xié)議
- 標(biāo)書代寫合作合同協(xié)議書
- DWI高信號常見疾病的鑒別診斷課件-2
- 2024年內(nèi)蒙古中考地理生物試卷(含答案)
- 2024年邵陽職業(yè)技術(shù)學(xué)院單招職業(yè)適應(yīng)性測試題庫完美版
- 2024年湖南理工職業(yè)技術(shù)學(xué)院單招職業(yè)適應(yīng)性測試題庫必考題
- 中國風(fēng)川劇戲曲京劇文化傳統(tǒng)文化國粹世界戲劇日活動策劃完整課件兩篇
- (正式版)JTT 1495-2024 公路水運危險性較大工程安全專項施工方案審查規(guī)程
- 醫(yī)院dip付費績效考核制度
- 20G520-1-2鋼吊車梁(6m-9m)2020年合訂本
- 電梯維護保養(yǎng)規(guī)則(TSG T5002-2017)
- 義務(wù)教育數(shù)學(xué)課程標(biāo)準(zhǔn)(2022年版)解讀與案例分析
評論
0/150
提交評論