面向?qū)ο蟪绦蛟O(shè)計多態(tài)性_第1頁
面向?qū)ο蟪绦蛟O(shè)計多態(tài)性_第2頁
面向?qū)ο蟪绦蛟O(shè)計多態(tài)性_第3頁
面向?qū)ο蟪绦蛟O(shè)計多態(tài)性_第4頁
面向?qū)ο蟪绦蛟O(shè)計多態(tài)性_第5頁
已閱讀5頁,還剩61頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、第九章 多態(tài)性本章概要: 多態(tài)性是面向?qū)ο蟪绦蛟O(shè)計的第四個基本特點。從字面上解釋,所謂多態(tài)性就是“有許多種形態(tài)”。基于這種理解,可以認為函數(shù)重載和運算符重載是多態(tài)性的最簡單形式。 面向?qū)ο蟪绦蛟O(shè)計 第二版051411但是,在面向?qū)ο蟪绦蛟O(shè)計領(lǐng)域,所謂多態(tài)性通常特指下述機制:派生類對象可以像基類對象一樣使用,同樣的消息既可以發(fā)送給基類對象也可以發(fā)送給派生類對象。2也就是說,在類等級的不同層次中可以共享一個行為的名字,但是不同層次中的類卻各自按自己的需要來實現(xiàn)這個行為。簡而言之:在不同的類層次中,同一個消息被不同的對象接收,產(chǎn)生了不同的行為。當一個對象接收到發(fā)送給它的消息時,根據(jù)該對象所屬于的類動

2、態(tài)選用在該類中定義的實現(xiàn)算法。3多態(tài)性機制不僅增加了面向?qū)ο筌浖到y(tǒng)的靈活性,進一步減少了冗余信息,而且顯著提高了軟件的可重用性和可擴充性。本章主要講述,靜態(tài)聯(lián)編與動態(tài)聯(lián)編,虛函數(shù)的聲明與使用,虛函數(shù)應(yīng)用實例,純虛函數(shù),多態(tài)性帶來的好處等內(nèi)容。 4本章快速索引面向?qū)ο蟪绦蛟O(shè)計 第二版9.1 靜態(tài)聯(lián)編與動態(tài)聯(lián)編 9.2 虛函數(shù)的聲明與使用9.3 虛函數(shù)應(yīng)用實例之一 9.4 純虛函數(shù)9.5 虛函數(shù)應(yīng)用實例之二 9.6 多態(tài)性帶來的好處 9.7 小結(jié)59.1 靜態(tài)聯(lián)編與動態(tài)聯(lián)編 所謂聯(lián)編(tinding),就是使一個計算機程序的不同部分彼此關(guān)聯(lián)的過程。 靜態(tài)聯(lián)編在編譯階段完成,因為所有聯(lián)編過程都在程

3、序開始運行之前完成,因此靜態(tài)聯(lián)編也叫先前聯(lián)編或早期聯(lián)編。 面向?qū)ο蟪绦蛟O(shè)計 第二版6編譯程序在編譯時并不確切知道應(yīng)把發(fā)送到對象的消息和實現(xiàn)消息的哪段具體代碼聯(lián)編在一起,而是在運行時才能把函數(shù)調(diào)用與函數(shù)體聯(lián)系在一起,則稱為動態(tài)聯(lián)編。 79.1.1靜態(tài)聯(lián)編對重載函數(shù)的調(diào)用是在編譯階段完成聯(lián)編的,有下述3種區(qū)分重載函數(shù)的方法:根據(jù)實參特征來區(qū)分。 使用作用域分辨符加以區(qū)分。 根據(jù)對象的類型來區(qū)分。 面向?qū)ο蟪绦蛟O(shè)計 第二版8下面讓我們看一個簡單程序例子:#include stdafx.h#include iostream.hclass Basepublic: void Who()cout I am

4、base classn;9class FirstDerived : public Basepublic:void Who() cout I am first derived classn;10class SecondDerived : public Basepublic: void Who()cout Who(); p = &first_obj;p - Who(); p = &second_obj; p - Who();first_obj.Who();second_obj.Who();運行輸出結(jié)果:I am base classI am base classI am base classI a

5、m first derived classI am second derived class129.1.2動態(tài)聯(lián)編 如果隨著指針P實際指向的對象不同,使用語句P-Who( );能夠調(diào)用不同類中Who的相同版本,我們就可以用相同的界面P-Who( )訪問函數(shù)Who的多個實現(xiàn)版本,從而也就能夠在程序運行時告訴用戶,當時指針P實際指向何類對象。面向?qū)ο蟪绦蛟O(shè)計 第二版13函數(shù)調(diào)用P-Who( )依賴于程序運行時P的值。虛函數(shù)提供的就是這樣一種機制。把由指針調(diào)用的成員函數(shù)聲明為虛函數(shù),則聲明為指向基類對象的指針,可以根據(jù)它在程序運行過程中當時實際指向的對象類型,通過動態(tài)聯(lián)編調(diào)用相應(yīng)類中的虛函數(shù)。14#

6、include class studentpublic:void calct()coutstudent xuefeiendl;class grastu:public studentpublic:void calct()coutgrastu xuefeiendl;15void fn(student &x)x.calct();void main()student s;grastu gs;fn(s);fn(gs);16為了把成員函數(shù)Who聲明為虛函數(shù),我們把上述程序修改為:#include stdafx.h#include iostream.hclass Basepublic: virtual vo

7、id Who()/定義Who()為虛函數(shù) cout I am base classn;面向?qū)ο蟪绦蛟O(shè)計 第二版17class FirstDerived : public Basepublic:void Who()cout I am first derived classn;18class SecondDerived : public Basepublic:void Who()cout Who();p = &first_obj;p - Who();p = &second_obj;p - Who();20運行結(jié)果如下:I am base classI am first derived classI

8、 am second derived class219.2 虛函數(shù)的聲明與使用 9.2.1聲明虛函數(shù)聲明虛函數(shù)的一般格式如下: virtual 函數(shù)原型; 必須首先在基類中聲明虛函數(shù)。 派生類中與基類虛函數(shù)原型完全相同的成員函數(shù),即使在說明時前面沒有冠以關(guān)鍵字virtual也自動成為虛函數(shù)。 面向?qū)ο蟪绦蛟O(shè)計 第二版229.2.1聲明虛函數(shù) 只有非靜態(tài)成員函數(shù)可以聲明為虛函數(shù)。 不允許在派生類中定義與基類虛函數(shù)名字及參數(shù)特征都相同,僅僅返回類型不同的成員函數(shù)。 編譯時出錯。 系統(tǒng)把函數(shù)名相同但參數(shù)特征不同的函數(shù)視為不同的函數(shù)。 通過聲明虛函數(shù)來使用C+提供的多態(tài)性機制時,派生類應(yīng)該從它的基類公

9、有派生。 面向?qū)ο蟪绦蛟O(shè)計 第二版23#include class studentpublic: virtual void calct(int x)coutstudent xuefei xendl;class grastu:public studentpublic:virtual void calct(float x)coutgrastu xuefei xendl;24void fn(student &x)int i=1;float j=9.8;x.calct(i);x.calct(j);void main()student s;grastu gs;fn(s);fn(gs);259.2.2使用

10、虛函數(shù)僅當程序中用指向基類對象的指針變量或引用基類對象的引用變量調(diào)用虛函數(shù)時,系統(tǒng)才以動態(tài)聯(lián)編方式實現(xiàn)對虛函數(shù)的調(diào)用 ,例如:面向?qū)ο蟪绦蛟O(shè)計 第二版26#include “stdafx.h”#include “iostream.h”class Apublic:/void show( )virtual void show( ) /必須要有virtual關(guān)鍵字,才能實現(xiàn)多態(tài)性cout AAA. endl;27class B : public Apublic:void show( ) /派生類中原型相同的函數(shù)可以不加關(guān)鍵字,/也被默認為虛函數(shù)cout BBB. endl;面向?qū)ο蟪绦蛟O(shè)計 第二版2

11、8class C : public Bpublic:void show( ) /派生類中原型相同的函數(shù)可以不加關(guān)鍵字,/也被默認為虛函數(shù)cout CCC. show();a_p = b_p ;/通過賦值形式,將派生類對象b的指針傳遞給基類對象指針a_p - show();/調(diào)用的接口形式不變,仍為“a_p-show()”,但調(diào)用的是b中的show()a_p = c_p ;/通過賦值形式,將派生類對象c的指針傳遞給基類對象指針a_p - show();/調(diào)用的接口形式不變,仍為“a_p-show()”,但調(diào)用的是c中的show()面向?qū)ο蟪绦蛟O(shè)計 第二版32運行結(jié)果:AAA BBB CCCAAA

12、 BBB CCC33關(guān)于程序的幾點說明:準備實現(xiàn)多態(tài)性的方法前面必須加關(guān)鍵字virtual,這被稱為虛函數(shù),是實現(xiàn)多態(tài)性的必要條件。使用多態(tài)性時,它的調(diào)用接口形式是不變的,關(guān)鍵是看基類對象的指針指向了哪個對象,就調(diào)用了哪個對象的方法。而這種指向有兩種表現(xiàn)形式:一種是通過實參、形參結(jié)合的形式;另一種是通過賦值語句的形式。面向?qū)ο蟪绦蛟O(shè)計 第二版34為了實現(xiàn)動態(tài)聯(lián)編,函數(shù)中參數(shù)類型必須是引用或者指針類型(如display(A *a);或display(A &a);)。通常用指向第一次定義虛函數(shù)的基類對象的指針來調(diào)用虛函數(shù),可以獲得運行時的多態(tài)性。(如例中使用“a_p - show();”調(diào)用,而沒

13、有使用其他派生類對象指針)35使用普通對象調(diào)用虛函數(shù)時,系統(tǒng)仍然以靜態(tài)聯(lián)編方式完成對虛函數(shù)的調(diào)用(如例中display(A a);),請讀者上機實踐。基類與派生類是相對的,因此,并非在任何情況下都必須首先在類等級的最高層類內(nèi)聲明虛函數(shù)。369.2.3 動態(tài)聯(lián)編的實現(xiàn)C +語言中的動態(tài)聯(lián)編是通過使用虛函數(shù)表(Virtual Function Table)來實現(xiàn)的,虛函數(shù)表也稱為v-表。 每個類的實例都有一個隱含的指向該類v-表的指針,當執(zhí)行諸如a_p - show()這樣的語句時,系統(tǒng)首先取a_p所實際指向的對象中的v-表指針,然后調(diào)用由這個v-表中指針項所指定的函數(shù)show(),從而實現(xiàn)了對不

14、同類的虛函數(shù)的調(diào)用。 面向?qū)ο蟪绦蛟O(shè)計 第二版379.3 虛函數(shù)應(yīng)用實例之一 下面是實現(xiàn)上述要求的程序:#include stdafx.h#include iostream.hclass Figureprotected:float x, y;public: void Set(float i, float j = 0) x = i; y = j;virtual void ShowArea() ;面向?qū)ο蟪绦蛟O(shè)計 第二版38class Triangle : public Figure public: void ShowArea() cout Triangle with height x and b

15、ase; cout y has an area of x * 0.5 * y n; ; 39class Square : public Figurepublic:void ShowArea() cout Square with dimension x * y;cout has an area of x * y n;面向?qū)ο蟪绦蛟O(shè)計 第二版9.3 虛函數(shù)應(yīng)用實例之一 40class Circle : public Figurepublic:void ShowArea()cout Circle with radius x;cout has an area of 3.14 * x * x Set(1

16、2.0, 8.0);p 1 = &s;p 1 - Set(12.0, 8.0);p 2 = &c;p 2 - Set(10.0);for(int i = 0;i ShowArea();面向?qū)ο蟪绦蛟O(shè)計 第二版42運行上列程序,得到下列輸出結(jié)果:Triangle with height 12 and base 8 has an area of 48Square with dimension 12 * 8 has an area of 96Circle with radius 10 has an area of 314439.4 純虛函數(shù) 純虛函數(shù)是在基類中聲明的虛函數(shù),它在聲明它的基類中沒有定義

17、,要求任何派生類都必須為該虛函數(shù)定義自己的版本。說明純虛函數(shù)的一般格式如下: virtual 函數(shù)原型 = 0;例如,為了把Figure類的虛函數(shù)ShowArea說明為純虛函數(shù),應(yīng)該像下面那樣聲明它:virtual void ShowArea() = 0;面向?qū)ο蟪绦蛟O(shè)計 第二版449.4 純虛函數(shù) 關(guān)于純虛函數(shù)和抽象類的使用,C+語言有以下規(guī)定:抽象類只能作為其他類的基類,不能聲明抽象類的實例。 在從抽象類派生出的新類中,必須重新定義其父類的每個純虛函數(shù);或者把這些函數(shù)繼續(xù)聲明為純虛函數(shù),這樣做派生類也就成為抽象類。面向?qū)ο蟪绦蛟O(shè)計 第二版459.4 純虛函數(shù) 在類等級的上層定義一個或幾個抽

18、象類作為基類,而在下層定義由基類派生出的具體類的情況比較常見,但是,不允許從具體類派生出抽象類。所謂具體類,就是不包含純虛函數(shù)的普通類。 在抽象類中也可以定義普通成員函數(shù)或虛函數(shù),雖然不能為抽象類聲明對象,但仍然可以通過派生類對象來調(diào)用這些不是純虛函數(shù)的函數(shù)。 面向?qū)ο蟪绦蛟O(shè)計 第二版469.5 虛函數(shù)應(yīng)用實例之二要求設(shè)計一個面向?qū)ο蟮某绦颍酝瓿上铝袔醉椆δ埽涸陲@示器熒光屏上指定位置顯示指定的圖形(點或圓),或擦去屏幕上正在顯示的某個圖形;放大或縮小屏幕上正在顯示的圓;把某個圖形從屏幕上原來的位置移動到指定的新位置;在屏幕上沿指定方向以指定的速度連續(xù)拖動指定的圖形。(參考教材請同學(xué)上機練習(xí))

19、面向?qū)ο蟪绦蛟O(shè)計 第二版47#include ”graphics.h”#include ”conio.h”enum Booleanfalse, true;class Locationprotected :int X;int Y;public :Location(int InitX, int InitY)X = InitX;Y = InitY;int GetX() return X; int GetY() return Y; ; 面向?qū)ο蟪绦蛟O(shè)計 第二版48class Point : public Locationprotected :Boolean Visible;public :Point(

20、int InitX, int InitY);virtual void Show();/ 虛函數(shù)virtual void Hide();/ 虛函數(shù)virtual void Drag(int DragBy);/ 虛函數(shù)Boolean IsVisible() return Visible; void MoveTo(int NewX,int NewY);面向?qū)ο蟪绦蛟O(shè)計 第二版49class Circle : public Pointprotected :int Radius;public :Circle(int InitX, int InitY, int InitRadius);void Show(

21、);/ 虛函數(shù)void Hide();/ 虛函數(shù)void Expand(int ExpandBy);void Contract(int ContractBy); 50Boolean GetDelta(int &DeltaX, int &DeltaY)char KeyChar;Boolean Quit;DeltaX = 0;DeltaY = 0;面向?qū)ο蟪绦蛟O(shè)計 第二版51doKeyChar = getch();/ 讀鍵盤輸入if(KeyChar = 13) return (false); / 回車鍵結(jié)束拖動if(KeyChar = 0)/ 擴展鍵碼Quit = true;/ 假設(shè)按對了鍵盤Ke

22、yChar = getch();/ 讀剩余的鍵碼switch(KeyChar)case 72 : DeltaY = -1;break;/ 上箭頭鍵case 80 : DeltaY = 1;break;/ 下箭頭鍵case 75 : DeltaX = -1;break;/ 左箭頭鍵case 77 : DeltaX = 1;break;/ 右箭頭鍵default : Quit = false;/ 錯鍵while(!Quit);/ 按錯了鍵可改敲return (true);/ 箭頭鍵繼續(xù)拖動 52Point Point(int InitX, int InitY) : Location(InitX,

23、InitY)Visible = false;/ 缺省為不可見狀態(tài)void Point Show()Visible = true;/ 可見狀態(tài)putpixel(X, Y, getcolor();/ 使用缺省顏色顯示面向?qū)ο蟪绦蛟O(shè)計 第二版53void Point Hide()Visible = false;/ 不可見狀態(tài)putpixel(X, Y, getbkcolor();/ 用背景色以擦去這個點void Point MoveTo(int NewX, int NewY)Hide();/ 使該點成為不可見X = NewX;/ 修改X,Y坐標到新位置Y = NewY;Show();/ 在新位置顯示

24、該點 54void Point :Drag(int DragBy)/ 參數(shù)為拖動的步長int DeltaX, DeltaY;int FigureX, FigureY;Show();/ 顯示欲拖動的圖形FigureX = X;/ 圖形初始位置FigureY = Y;while(GetDelta(DeltaX, DeltaY) / 下面是完成拖動操作的循環(huán)語句FigureX += (DeltaX * DragBy);/ 修改坐標值FigureY += (DeltaY * DragBy);MoveTo(FigureX,FigureY);55Circle :Circle(int InitX, int

25、InitY, int InitRadius) : Point(InitX, InitY)Radius = InitRadius;void Circle :Show()Visible = true;circle(X, Y, Radius);/ 畫圓 56void Circle :Hide()int TempColor;TempColor = getcolor();/ 保存當前前景色setcolor(getbkcolor();/ 令背景色為畫圓的顏色Visible = false;circle(X, Y, Radius);/ 用背景色畫圓setcolor(TempColor);/ 恢復(fù)當前前景色面

26、向?qū)ο蟪绦蛟O(shè)計 第二版57void Circle : Expand(int ExpandBy)Hide();/ 擦去舊圓Radius += ExpandBy;/ 擴大半徑if(Radius 0)/ 避免半徑值為負數(shù)Radius = 0;Show();/ 顯示新圓void Circle :Contract(int ContractBy)Expand(- ContractBy);/ 用Radius-ContractBy為半徑畫圓 58void main()int graphdriver = DETECT,graphmode;initgraph(&graphdriver,&graphmode,”.

27、bgi”);Circle MyCircle(100,200,50);/ 說明一個Circle對象MyCircle.Show();/ 顯示它getch();/ 等待按下任意鍵MyCircle.MoveTo(200,250);/ 移動圓getch();MyCircle.Expand(50);/ 放大圓getch();MyCircle.Contract(75);/ 縮小圓getch();MyCircle.Drag(5);/ 拖動圓closegraph();面向?qū)ο蟪绦蛟O(shè)計 第二版599.6多態(tài)性帶來的好處多態(tài)性主要帶來以下幾點好處: 在類等級的不同層次中,完成相同功能的成員函數(shù)使用相同名字,在程序運行時根據(jù)調(diào)用該函數(shù)的指針實際指向的對象的類型,動態(tài)地決定使用該函數(shù)的哪個版本。 進一步減少了信息冗余。 顯著提高了程序的可重用性和可擴充性,因而進一步提高了程序的可維護性。 面向?qū)ο蟪绦蛟O(shè)計 第二版609.6多態(tài)性帶來的好處 例如,擴充上節(jié)的程序,使它增加移動和拖動弧形對象的功能。為此,僅需像下面那樣定義新的派生類Arc,對原有程序一點也不需改動: 面向?qū)ο蟪绦蛟O(shè)計 第二版61class Arc : public Circleint StartAngle;int EndAng

溫馨提示

  • 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)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論