![第5章C++語言進階_第1頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/28/b9d32d94-de8d-4dbc-9f8a-3938ad0bc05d/b9d32d94-de8d-4dbc-9f8a-3938ad0bc05d1.gif)
![第5章C++語言進階_第2頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/28/b9d32d94-de8d-4dbc-9f8a-3938ad0bc05d/b9d32d94-de8d-4dbc-9f8a-3938ad0bc05d2.gif)
![第5章C++語言進階_第3頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/28/b9d32d94-de8d-4dbc-9f8a-3938ad0bc05d/b9d32d94-de8d-4dbc-9f8a-3938ad0bc05d3.gif)
![第5章C++語言進階_第4頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/28/b9d32d94-de8d-4dbc-9f8a-3938ad0bc05d/b9d32d94-de8d-4dbc-9f8a-3938ad0bc05d4.gif)
![第5章C++語言進階_第5頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/28/b9d32d94-de8d-4dbc-9f8a-3938ad0bc05d/b9d32d94-de8d-4dbc-9f8a-3938ad0bc05d5.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、第5章C+語言進階教學提示:在第4章已經(jīng)介紹了C+中關(guān)于類的大部分內(nèi)容,本章繼續(xù)講解和類相關(guān)的內(nèi)容。主要包括:友元,this指針,類的繼承,多態(tài)和虛擬函數(shù)等,它們是編寫面向?qū)ο蟪绦虻幕A。教學目標:掌握友元函數(shù)和友元類的概念,掌握友元的使用,理解友元的局限性;理解this指針的概念;理解多態(tài)性的含義,多態(tài)對于繼承的意義,掌握多態(tài)的工作原理;理解抽象類與具體類的區(qū)別;熟練運用類的繼承、類的多重繼承、虛函數(shù)、純虛函數(shù),編寫層次分明、結(jié)構(gòu)清晰的程序。5.1 友元和this指針5.1.1 友元1. 友元函數(shù)在第3章重載運算符時已經(jīng)用到了友元函數(shù),但并沒有對友元函數(shù)作詳細的介紹。其實,友元函數(shù)和普通的C
2、+函數(shù)不同的只是,它可以訪問類的保護和私有成員。利用友元函數(shù)使程序編寫更加方便,提高了效率。但是使用友元函數(shù)破壞了類的封裝性,因此一般只在能夠提高程序效率的前提下使用友元。定義友元函數(shù)很簡單,在類里聲明一個普通函數(shù),標上關(guān)鍵字friend,就成了該類的友元,就可以訪問該類的一切成員。例如,下面的例子定義了兩個類,rect類和point類,并聲明函數(shù)inrect是它們的友元函數(shù),因此inrect函數(shù)可以訪問rect類和point類中的非公有成員。 class rect; class point private: int x; int y; public: point(int xx=0,int y
3、y=0):x(xx),y(yy) ; friend int inrect(const point&,const rect&);/聲明友元函數(shù) ; class rect private: point p1; point p2; public: rect(int x1,int y1,int x2,int y2):p1(xl,y1),p2(x2,y2) ; friend int inrect(const point&,const rect&);/聲明友元函數(shù) ; /友元函數(shù)的定義 int inrect(const point &p,const rect &r) /友元函數(shù)內(nèi)可以訪問類的私有成員 if
4、(p.x=r.p2.x)&(p.y=r.p2.y) return l; if(p.x=r.p1.x)&(p.x=r.p1.y)&(p.y=r.p2.y) return 1; return 0; 友元函數(shù)不是類的成員函數(shù),但它是類的朋友,因而友元函數(shù)也可以訪問類的全部成員。友元函數(shù)的聲明可以放在類定義的任何部位,可以在public區(qū),也可以放在private區(qū),意義完全相同。友元函數(shù)的定義部分在類定義體的外面,一般和類的成員函數(shù)放在一起,以便在類重用時,友元函數(shù)可以一起重用。2.友元成員函數(shù)當一個類的某個成員函數(shù)被宣布為另一個類的友元時,在這個成員函數(shù)內(nèi)就可以訪問另一個類的非公有數(shù)據(jù)。例如: c
5、lass student; class teacher public: void teacher:setscore(student &s,int i) s.score=i; ; class student private: int score; public: friend void teacher:setscore(student &s,int i); ; teacher類的成員函數(shù)setscore(student&s,int i) 被聲明為student類的友元,因此teacher類的對象可以通過其成員函數(shù)setscore修改student類對象的非公有數(shù)據(jù)成員。例如: student s
6、1; teacher t1; t1.setscore(s1,90);3. 友類整個類是另一個類的友元,該友元稱為友類,友類的每個成員函數(shù)都可以訪問另一個類的保護或私有的數(shù)據(jù)成員。即,當類A宣布為類B的友類時,類A的所有成員函數(shù)都可以訪問類B的非公有成員。例如: class student; class teacher public: void teacher:setscore(student &s,int i) s.score=i; ; class student private: int score; public: friend class teacher;/友類 / ;友元的作用主要是為
7、了提高效率和方便編程,但隨著硬件性能的迅速提高,友元的這點作用已經(jīng)微不足道,相反,友元破壞了類的封裝性,破壞了類的整體操作。所以我們不鼓勵使用友元,讀者在使用友元時要權(quán)衡利弊。5.1.2 this指針this指針隱含于每一個類的成員函數(shù)中(靜態(tài)成員函數(shù)除外),它指向調(diào)用該成員函數(shù)的對象。當一個對象調(diào)用成員函數(shù)時,編譯程序先將對象的指針地址賦值給this指針,然后調(diào)用成員函數(shù),每次成員函數(shù)存取數(shù)據(jù)時都隱含地使用了this指針。通常不顯式地使用this指針來引用數(shù)據(jù)成員??梢杂?this來標識調(diào)用成員函數(shù)的對象。 class room private: int m; public: room(in
8、t i,int j); void view( ) cout”m=”mendl; /隱含了this指針 cout”m=”mendl;/和上一行的效果相同 ; 例題:分析下面程序的輸出結(jié)果:/5_1.cpp#include class sampleprivate:int x,y;public:sample( ) sample(int a,int b)x=a;y=b;void copy(sample &c)if(this=&c)cout錯誤的復制調(diào)用endl;/return;elsec.view();void square()x=x*x;y=y*y;void view()coutx=x y=yend
9、l;void main()sample c1,c2(5,5);c2.square();c2.view();c2.copy(c2);c1.copy(c2);程序的執(zhí)行結(jié)果是: 25 25 錯誤的復制調(diào)用 25 255.2 靜態(tài)成員為了解決數(shù)據(jù)的共享問題,C+中提出了靜態(tài)成員的概念。靜態(tài)成員分為靜態(tài)成員函數(shù)和靜態(tài)成員變量兩種。將數(shù)據(jù)成員聲明為靜態(tài)的,將使所有的同類對象都擁有同一份靜態(tài)成員,該靜態(tài)成員遵守數(shù)據(jù)封裝約定。使用靜態(tài)成員可以節(jié)省內(nèi)存,因為它是所有對象共有的,只需存儲一處,就可以供所有對象使用。靜態(tài)成員對所有的對象都一樣,它的值是可以改變的。類的所有對象都共用static類成員。關(guān)鍵字sta
10、tic可以用來定義類的成員。如果將類的某個成員聲明為static,那么你也就告訴編譯器:無論創(chuàng)建了多少個類對象,程序中也只有一個static成員的副本。也就是說,類的所有對象都將共用static成員。如果在創(chuàng)建第一個類對象時沒有對static成員進行初始化,那么類中所有的static成員都被初始化為零。當你在類中聲明一個static成員時,你并沒有定義它,所以必須為這個static成員提供一個在類作用域之外的全局定義。我們通過在全局作用域中重新聲明static成員變量來定義它,并且使用作用域解析運算符來指定它所在的類。在程序中對static成員變量的定義為static成員變量分配了內(nèi)存空間。5
11、.2.1 靜態(tài)數(shù)據(jù)成員靜態(tài)數(shù)據(jù)成員的使用方法:(1) 靜態(tài)數(shù)據(jù)成員在聲明時前面加static關(guān)鍵字。(2) 靜態(tài)數(shù)據(jù)成員的初始化和一般數(shù)據(jù)成員的初始化不同,靜態(tài)數(shù)據(jù)成員初始化格式如下: :=;初始化在類體外進行,前面不加static,以免與一般的靜態(tài)變量或者對象混淆。初始化時不加該成員的訪問權(quán)限控制符public、protected和private。初始化時使用作用域運算符表明該成員所屬的類,因此,靜態(tài)數(shù)據(jù)成員是類的成員,它不是任何對象獨占的成員。(3) 靜態(tài)數(shù)據(jù)成員必須初始化。(4) 用類名引用靜態(tài)數(shù)據(jù)成員: :(5) 類和對象都可以對靜態(tài)數(shù)據(jù)成員進行改動。下面的示例程序使用到了static
12、變量,請仔細閱讀程序并理解程序是如何運行的。/補充例題:(5_2_1.cpp)注意,我們在類ShareVar中聲明了靜態(tài)整數(shù)變量num,同時還在程序中將num作為一個全局變量來定義。前面提到過,這樣做是必須的,因為在類ShareVar中我們只是聲明變量num而沒有為它分配內(nèi)存。由于在程序中沒有對變量num作初始化,所以C+默認將num初始化為0,因此第一次調(diào)用函數(shù)shownum()時,程序輸出0。接下來,對象a將num的值設置為10。然后,對象a和b都調(diào)用函數(shù)shownum()來輸出num的值。因為在程序中變量num只有一個副本,并且由對象a和b共用,所以兩個函數(shù)都將輸出10。#include
13、 class ShareVar static int num;public: void setnum(int i) num = i; ; void shownum() cout num ; ;/ 定義類ShareVar的靜態(tài)成員變量numint ShareVar : num ; int main() ShareVar a, b; a.shownum(); / 輸出 0 b.shownum(); / 輸出 0a. setnum(10); / 將靜態(tài)成員變量num的值設為10 a.shownum(); / 輸出 10 b.shownum(); / 也輸出 10 return 0;l 記?。喝绻陬?/p>
14、中某個成員被聲明為static,那么這個成員在程序中就只有一個副本,然后類的所有對象都將共用這個副本。如果static成員變量是類的公有成員,那么可以直接通過類的名字而不是對象的名字來使用這個成員(當然,也可以通過對象的名字來使用)。例如,考慮下面的類ShareVar:class ShareVarpublic: static int hum; void setnum(int i) num = i; ; void shownum() cout num ; ;在上面的定義中,成員變量num是公有的,因此可以直接訪問變量num,如下所示:ShareVar:num=100;上面這條語句是通過類的名字和
15、作用域解析運算符來訪問變量num,這與類的對象無關(guān)。而且,甚至在任何ShareVar類型的對象存在之前,這條語句都是有效的!這樣,你可以在創(chuàng)建任何對象之前獲得或者設置類的static成員變量的值。下面的程序定義了一個靜態(tài)數(shù)據(jù)成員n,在構(gòu)造函數(shù)中定義了n的自增運算,調(diào)用一次構(gòu)造函數(shù),n加1。/5_2.cpp#include class roomprivate: int m;public: static int n; /聲明靜態(tài)數(shù)據(jù)變量 room(int i):m(i) n+; void view() coutm=mendl; coutn=nendl; room( ) ;int room:n=0;
16、 /靜態(tài)成員只能在類外部定義,定義的同時必須初始化。void main() room r1(10);/每當調(diào)用一次構(gòu)造函數(shù),n加1。 room r2(20);/r2構(gòu)造結(jié)束后n=2 room r3(30);/r3構(gòu)造結(jié)束后n=3 coutin class room n=room:nendl;/引用靜態(tài)成員可以用類名程序的執(zhí)行結(jié)果是: in class room n=35.2.2 靜態(tài)成員函數(shù)成員函數(shù)也可以被聲明為static,但這種用法并不普遍。靜態(tài)成員函數(shù)和靜態(tài)數(shù)據(jù)成員一樣,它們都屬于類的靜態(tài)成員,而不是對象的成員。static成員函數(shù)可以通過類的對象來調(diào)用,或者也可以不依賴于任何對象而使用
17、類的名字和作用域解析運算符來調(diào)用。在靜態(tài)成員函數(shù)的實現(xiàn)中不能直接引用類的非靜態(tài)成員,也不能引用this指針,但可以引用類中聲明的靜態(tài)成員(當然,static成員函數(shù)也可以訪問全局變量和全局函數(shù))。如果靜態(tài)成員函數(shù)中需要引用非靜態(tài)成員時,可以通過對象來引用。下面的類room定義了靜態(tài)成員函數(shù)view();它可以引用類的靜態(tài)成員變量n,但是不能引用非靜態(tài)成員變量m。 class room private: int m; public: static int n; room(int i):m(i) n+; static void view( ) /靜態(tài)成員函數(shù) m+; /error這里不能引用非靜態(tài)
18、成員 cout”n=”nendl; ;int room:n=0;/定義并初始化靜態(tài)數(shù)據(jù)成員n=0下面的程序定義了一個學生類,該類共定義了4個靜態(tài)成員,一個整型靜態(tài)成員變量count,它的作用是計數(shù)器,用來記錄學生的個數(shù);一個student類類型的指針靜態(tài)成員變量pfirst,用來記錄鏈頭指針;一個返回值為空的靜態(tài)成員函數(shù)findname(),它的功能是從鏈頭開始查找某個特定的節(jié)點,函數(shù)體內(nèi)設置了一個for循環(huán),循環(huán)從鏈頭開始查找,一直查到鏈尾,如果找到了關(guān)鍵節(jié)點,則輸出關(guān)鍵節(jié)點在鏈表中的位置,結(jié)束循環(huán),如果沒有找到則輸出“no find并返回;一個返回值為空的靜態(tài)成員函數(shù)view(),它的功能
19、是對鏈表進行遍歷,并在屏幕上依次輸出各個節(jié)點的name域的值。調(diào)用一次student類的成員函數(shù),就在鏈表頭插入一個節(jié)點,新插入節(jié)點的pnext指針指向插入前的頭節(jié)點。鏈表開始時為空,即pfirst為空。具體代碼如下:/5_3.cpp#include #include class studentprivate:char name40;int number;static int count; /計數(shù)器,用來記錄學生的個數(shù)static student* pfirst; /鏈表頭指針,student *pnext; /指向鏈表當前節(jié)點的下一個節(jié)點public:student(char *);stud
20、ent();static void findname(char *); /查詢特定節(jié)點static void view(); /遍歷鏈表;int student:count=0; /定義并賦初值0student* student:pfirst=NULL; /定義并賦初值NULL/student類的成員函數(shù)student:student(char *pname)strcpy(name,pname);pnext=pfirst;pfirst=this;count+;number=count;/student類的析構(gòu)函數(shù)student:student( ) /析構(gòu)函數(shù)if(pfirst=this)pf
21、irst=pnext;count-;return;for(student* ps=pfirst;ps;ps=ps-pnext)if(ps-pnext=this)ps-pnext=pnext;count-;return;void student:findname(char* pname) /在鏈表中查找某個關(guān)鍵節(jié)點for(student* ps=pfirst;ps;ps=ps-pnext)if(strcmp(ps-name,pname)=0)coutfind it,it is number numberendl;return;coutno findpnext)coutnameendl;void
22、main()student s1(s1);student s2(s2);student s3(s3);student:view();char name40;coutplease put in the name of which you want to findname;student:findname(name);程序運行結(jié)果如下: sl s2 s3 please put in the name of which you want to find s2(假如你輸入的是s2) find it,it is number 25.3 繼 承繼承性是面向?qū)ο蟪绦蛟O計中最重要的機制,這一機制提供了無限重復
23、利用程序資源的有效途徑,該機制自動為一個類提供來自另一個類的操作和數(shù)據(jù)結(jié)構(gòu)。程序員通過C+語言中的繼承機制,可以擴充舊的程序以適應新的需求,這樣不僅可以節(jié)約程序開發(fā)時間和資源,并且可以為未來的程序設計增添新的資源。理解繼承性是理解面向?qū)ο蟪绦蛟O計所有方面的關(guān)鍵。5.3.1 基類和派生類C+語言的繼承機制,允許我們利用已有的數(shù)據(jù)類型定義新的數(shù)據(jù)類型,所定義的新數(shù)據(jù)類型不僅擁有新定義的成員,而且還同時擁有舊的成員。我們稱用來派生新類的類為基類,又叫做父類。由基類派生的新類稱為派生類,也稱為子類。一個派生類可以從一個基類派生,也可以從多個基類派生。從一個基類派生的繼承方式叫做單繼承;從多個基類派生的
24、繼承方式叫做多繼承。任何類都可以作為基類,一個基類可以有一個或者多個派生類,一個派生類還可以成為另一個類的基類。定義單繼承派生類的一般格式如下: class : / 派生類新定義的成員 其中,派生類名稱是新定義的類名,它是從父類中派生的,并且是按照指定的繼承方式派生的。繼承方式有3種,分別是:public方式,表示公有類繼承;protected方式,表示保護基類;private方式,表示私有基類。其中private方式是默認的繼承方式。派生類3種繼承方式的異同闡述如下:(1) public方式這種方式將基類的protected區(qū)成員繼承到派生類的protected區(qū),基類的public區(qū)的成員
25、繼承到派生類的public區(qū)。這時基類能作的所有操作,派生類都可以完成,派生類是基類的子類。對于派生類來說,基類的公有成員和保護成員可見,基類的私有成員不可見,派生類不可以訪問基類的私有成員。對于派生類對象來說,派生類的對象可以訪問基類的公有成員,其他成員是不可見的。注意:在公有繼承時,派生類的對象可以訪問基類的共有成員,派生類的成員函數(shù)可以訪問基類的共有成員和保護成員。(2) protected方式這種方式將基類的protected區(qū)和public區(qū)的所有成員都繼承到派生類的protected區(qū)。在這種繼承方式下派生類不是基類的子類。對于派生類來說,基類的公有成員和保護成員是可見的,基類的保
26、護成員和公有成員都作為派生類的保護成員,并且不能被這個派生類的子類訪問;而基類的私有成員是不可見的,派生類不能訪問基類的私有成員:對于派生類的對象來說,基類的所有成員都不可見。所以對于保護繼承來說,基類的成員只能由直接派生類訪問,而無法再往下繼承。(3) private方式將基類的protected區(qū)和public區(qū)的所有成員都繼承到派生類的private區(qū)。在這種繼承方式下派生類也不是基類的子類。對于派生類來說,而基類的公有成員和保護成員是可見的,基類的保護成員和公有成員都作為派生類的私有成員,并且不能被這個派生類的子類訪問:而基類的私有成員是不可見的,派生類不能訪問基類的私有成員;對于派生
27、類的對象來說,基類的所有成員都不可見。所以對于私有繼承來說,基類的成員只能由直接派生類訪問,而無法再往下繼承。如果基類與派生類中都有用戶自定義的構(gòu)造函數(shù),基類的構(gòu)造由基類的構(gòu)造函數(shù)完成,派生類的構(gòu)造函數(shù)負責提供派生類和基類的構(gòu)造參數(shù)并構(gòu)造派生類。由于構(gòu)造函數(shù)不能被繼承,所以派生類的構(gòu)造函數(shù)必須通過調(diào)用基類的構(gòu)造函數(shù)來初始化基類的對象。因而在定義派生類的構(gòu)造函數(shù)時,除了對自己的數(shù)據(jù)成員進行初始化外,還必須負責調(diào)用基類構(gòu)造函數(shù),初始化基類的數(shù)據(jù)成員。派生類的構(gòu)造函數(shù)一般格式如下:():(), () / 派生類數(shù)據(jù)成員初始化派生類構(gòu)造函數(shù)的調(diào)用順序如下:(1) 基類的構(gòu)造函數(shù)(2) 子對象類的構(gòu)造函
28、數(shù)(3) 派生類的構(gòu)造函數(shù)當對象被刪除時,派生類的析構(gòu)函數(shù)被執(zhí)行。由于析構(gòu)函數(shù)也不能被繼承,因此在執(zhí)行派生類的析構(gòu)函數(shù)時,基類的析構(gòu)函數(shù)也將被調(diào)用。執(zhí)行順序是先執(zhí)行派生類的析構(gòu)函數(shù),再執(zhí)行基類的析構(gòu)函數(shù),與執(zhí)行構(gòu)造函數(shù)時的順序正好相反。5.3.2 多重繼承多繼承的一般格式:class :,其中,基類可以有兩個或者兩個以上,各個基類之間用逗號隔開,每個基類名前都指明繼承方式,默認的繼承方式是private方式。例如,下面的程序中,類C繼承于兩個基類,一個基類是A,另一個基類是B。/5_4.cpp#include class A /基類A的定義int a;public:A(int i)a=i;co
29、utA constructorendl;void view( )couta=aendl;class B /基類B的定義int b;public:B(int j)b=j;coutB constructorendl;void view()coutb=bendl;class C:public A,public B /定義子類C,它繼承于基類A和基類Bint c;public:/派生類c的構(gòu)造函數(shù)在初始化自己的數(shù)據(jù)成員時,必須負責調(diào)用基類構(gòu)造函數(shù)初始化基類的數(shù)據(jù)成員。C(int k):A(+k),B(-k)c=k;coutC constructorendl;void view( )A:view( );
30、B:view( );coutc=cendl;void main()C c1(10);c1.view();本程序的執(zhí)行結(jié)果是: A constructor B constructor C constructor a=1l b=10 c=105.4 多態(tài)性與虛擬函數(shù)學習目標:l 理解多態(tài)性的概念l 理解如何聲明和利用虛擬函數(shù)來實現(xiàn)多態(tài)性l 理解抽象類和具體類的區(qū)別l 理解C+如何實現(xiàn)虛擬函數(shù)和動態(tài)綁定5.4.1 多態(tài)性C+允許子類的成員函數(shù)重載父類的成員函數(shù),程序在運行時能夠依據(jù)其類型確認調(diào)用哪個函數(shù)的能力,稱為多態(tài)性。多態(tài)性是面向?qū)ο蟪绦蛟O計的重要特性,是指同一個接口名稱具有多種功能。利用多態(tài)性
31、,用戶只需發(fā)送一般形式的消息,而將所有的實現(xiàn)留給接收消息的對象,對象根據(jù)所接收的消息做相應的操作。函數(shù)重載和運算符重載就是一類簡單的多態(tài)性。如果語言不支持多態(tài),則不能稱其是面向?qū)ο蟮恼Z言。只支持類不支持多態(tài)的語言,我們稱其為基于對象的。如Ada語言、Visual Basic語言。為了指明某個成員函數(shù)具有多態(tài)性,必須用關(guān)鍵字virtual聲明其為虛擬函數(shù)。例如,下面的程序在它的基類中定義了虛函數(shù)fn( ),在派生類中又重新定義了虛函數(shù)fn( ),因此實現(xiàn)了多態(tài)的功能。/5_5.cpp#include class Basepublic:virtual void fn( )如果基類中的一個函數(shù)(例如
32、fn())被聲明為virtual,用基類的指針或引用來指明派生類對象并用該指針或引用來調(diào)用該函數(shù),程序會根據(jù)對象的類型動態(tài)選擇相應的派生類的fn()函數(shù)。這就是動態(tài)綁定。如果用對象和圓點(.)運算符調(diào)用該函數(shù)(如der.fn( ))則是靜態(tài)綁定(即是在編譯時確定的)。 coutin base classendl;class Derive:public Basepublic:virtual void fn( )coutin derive classendl;在test( )函數(shù)中,b是基類Base的引用形參,Base類對象和Derive對象都可以作為參數(shù)傳遞給b。而fn( )是Base類的虛函數(shù)
33、,所以b.fn()的調(diào)用要到運行時才能確定調(diào)用的是基類的fn( )還是派生類的fn( )。;void test(Base &b)b.fn();void main()由于函數(shù)fn( )標識為虛函數(shù),編譯時系統(tǒng)遇到b.fn( )后,會將其作為后期綁定處理,保證在運行時確定調(diào)用的是基類的fn( ),還是派生類的fn( )。Base b;Derive der;coutcalling test(b)endl;test(b);coutcalling test(der)endl;test(der);程序運行結(jié)果為: calling test(b) in base class calling test(der
34、) in derive class編譯通常是在前期綁定狀態(tài)下工作的,只有對于虛函數(shù),才把它作為后期綁定來實現(xiàn)。多態(tài)性增加了一些數(shù)據(jù)存儲和執(zhí)行指令的開銷,但是在多數(shù)情況下,這種額外的開銷不會對程序運行效率有大的影響。因此,在類中應將成員函數(shù)盡可能設為虛函數(shù)。綁定是指一個計算機程序自身彼此關(guān)聯(lián)的過程。按照綁定所進行的階段不同,可分為前期綁定和后期綁定。又稱為靜態(tài)綁定和動態(tài)綁定。前期綁定是指綁定工作出現(xiàn)在編譯鏈接階段,這種綁定過程在程序開始運行之前已經(jīng)完成。也叫做靜態(tài)聯(lián)編或靜態(tài)綁定。后期綁定是指編譯程序在編譯階段不能確定將要調(diào)用的函數(shù),只有在程序運行時才能確定要調(diào)用的函數(shù),為此要求綁定工作在程序運行
35、時進行。這種在程序運行時進行的綁定工作稱為后期綁定,也叫做動態(tài)聯(lián)編或動態(tài)綁定。5.4.2 虛擬函數(shù)虛擬函數(shù)(virtual function)指的是某個函數(shù)在基類中被聲明為virtual,而在派生類中又重新定義了這個函數(shù)。虛擬函數(shù)是動態(tài)綁定的基礎。虛擬函數(shù)是成員函數(shù),而且是非靜態(tài)的成員函數(shù)。聲明虛擬函數(shù)的語法形式為:virtual 函數(shù)類型 函數(shù)名稱( )其中virtual是聲明虛擬函數(shù)的關(guān)鍵字。虛擬函數(shù)簡稱為虛函數(shù)。如果一個類的成員函數(shù)聲明為虛函數(shù),這就意味著該成員函數(shù)可能在它的派生類中有不同的實現(xiàn)。動態(tài)綁定只能通過指針或者引用標識對象來操作虛函數(shù),當聲明一個指向基類的指針時,該指針也適用于
36、相應的派生類。如果使用一般類型標識對象操作虛函數(shù),則將采用靜態(tài)綁定方式調(diào)用虛函數(shù)。例如:/5_6.cpp#include class basepublic:virtual void f1()coutf1 function of baseendl;virtual void f2()coutf2 function of baseendl;virtual void f3()coutf3 function of baseendl;void f4() /一般成員函數(shù)coutf4 function of baseendl;class subclass:public basepublic:virtual v
37、oid f1() /多態(tài)coutf1 function of subclassendl;virtual void f2(int x) /參數(shù)不同無法實現(xiàn)多態(tài)coutf2 function of subclassendl;virtual void f4() /在基類中沒有被聲明虛函數(shù),不能實現(xiàn)多態(tài)coutf4 function of subclassf1();p-f2();p-f3();p-f4(); p=≻p-f1();p-f2();p-f3();/在子類subclass中沒有重載父類base的成員函數(shù)f3(),不能實現(xiàn)多態(tài)p-f4();程序的運行結(jié)果是:f1 function of b
38、asef2 function of basef3 function of basef4 function of basef1 function of subclassf2 function of basef3 function of basef4 function of base由上面的程序可以看出:(1) 虛函數(shù)在基類與派生類中的聲明(包括函數(shù)名、返回值類型和參數(shù)列表)必須一樣才能實現(xiàn)多態(tài)。(2) 只有類的成員函數(shù)才能聲明為虛函數(shù)。(3) 內(nèi)聯(lián)函數(shù)、構(gòu)造函數(shù)(調(diào)用時產(chǎn)生)、靜態(tài)成員函數(shù)(不屬于對象)不能聲明為虛函數(shù)。(4) 對虛函數(shù)調(diào)用的解釋取決于調(diào)用它的對象。(5) 對非虛函數(shù)調(diào)用的解釋取
39、決于調(diào)用它的指針或引用的類型。5.4.3 純虛函數(shù)和抽象類純虛函數(shù)是一種特殊的虛函數(shù),它的定義格式是:virtual ()=0;在許多情況下,在基類中不能對虛函數(shù)給出有意義的實現(xiàn),而把它聲明為純虛函數(shù),實現(xiàn)留給基類的派生類做。抽象類:帶有純虛函數(shù)的類是抽象類。抽象類是一種特殊的類,它是為了抽象和設計的目的而建立的,抽象類的作用是將子類組織在一個繼承層次結(jié)構(gòu)中,給子類提供一個公共的根。抽象類的特點: 抽象類只能做其他類的基類,不能建立抽象類的對象。 抽象類不能用作參數(shù)類型、函數(shù)返回類型。 抽象類可以聲明指針和引用,指針指向它的派生類,實現(xiàn)多態(tài)性。例如,下面的程序定義了一個抽象類shape,該類中
40、包含一個純虛函數(shù)view()的聲明,在它的派生類rect(長方形)、square()正方形和circle(圓)中分別對純虛函數(shù)view()定義了不同的實現(xiàn)。/5_7.cpp#include const double pi=3.1415;class shape /抽象類protected:double x,y;public:void setvalue(int i,int j=0)x=i;y=j;virtual void view( )=0; /純虛函數(shù);class rect:public shapepublic:void view()cout長方形面積是:x*yendl;class square
41、:public shapepublic:void view()cout正方形面積是:x*xendl;class circle:public shapepublic:void view()cout圓面積是:pi*x*xsetvalue(3 , 5);p0-view();p1=&s;p1-setvalue(3);p1-view();p2=&c;p2-setvalue(3);p2-view();程序運行結(jié)果如下: 長方形面積是:15 正方形面積是:9 圓面積是:28.27355.5 虛擬析構(gòu)函數(shù)在析構(gòu)函數(shù)前面加上virtual關(guān)鍵字,則析構(gòu)函數(shù)被聲明為虛擬析構(gòu)函數(shù),虛擬析構(gòu)函數(shù)的格式如下: clas
42、s virtual ( ); ;如果基類的析構(gòu)函數(shù)被聲明為虛擬析構(gòu)函數(shù),那么它的派生類的析構(gòu)函數(shù)也是虛擬的。虛擬析構(gòu)函數(shù)的目的是在用delete運算符刪除對象時,能保證析構(gòu)函數(shù)被正確地執(zhí)行。因為設置虛擬析構(gòu)函數(shù)后,是用動態(tài)綁定的方式選擇析構(gòu)函數(shù)的。例如,下面的程序在基類base中析構(gòu)函數(shù)被定義為虛擬析構(gòu)函數(shù),派生類der的析構(gòu)函數(shù)也被定義為虛擬析構(gòu)函數(shù)。在main主函數(shù)中定義了一個基類的指針b,指向派生類的對象。/5_8.cpp#include class basepublic:virtual base() /聲明為虛擬析構(gòu)函數(shù)coutdestructing baseendl;class de
43、r:public basepublic:char *ch;der(int i)ch=new chari;virtual der() /聲明為虛擬析構(gòu)函數(shù)delete ch;coutdestructing derendl;void main()base *b=new der(20);delete b;程序的運行結(jié)果是: destructing der destructing base假如在基類base中析構(gòu)函數(shù)不用虛函數(shù),則輸出結(jié)果如下: destucting base5.6 上機指導5.6.1 類的繼承編寫一個統(tǒng)計動物種類的程序。目的:練習應用類的繼承,加深理解繼承的概念,在定義類時活學活用類
44、的繼承。首先聲明一個名為Animal(動物)的基類,然后再創(chuàng)建兩個派生類,一個是Mammal(哺乳動物),一個是Bird(鳥類)。子類Mammal含有子女數(shù)和讀取子女數(shù)的成員函數(shù)NumOffspring();子類Bird含有生蛋數(shù)、是否筑巢,以及取生蛋數(shù)的成員函數(shù)GetEggs( )。成員函數(shù)ShowMannal()和ShowBird()的功能是分別輸出各自的對象參數(shù)。程序的具體源代碼如下:/5_9.cpp#include #include #define FALSE 0#define TRUE 1/Animal類定義class Animalpublic:Animal(const char *s) /構(gòu)造函數(shù)strn
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- PB-22-5-Hydroxyquinoline-isomer-生命科學試劑-MCE-7761
- 1-Boc-4-carboxymethyl-piperazine-生命科學試劑-MCE-6310
- 2025年度公共停車場車位使用權(quán)抵押合同范例
- 二零二五年度離婚后小孩撫養(yǎng)費及生活費用監(jiān)管協(xié)議
- 二零二五年度早餐車餐飲合作經(jīng)營協(xié)議
- 施工現(xiàn)場施工排水排泥管理制度
- 施工現(xiàn)場施工防地震災害制度
- 教育領(lǐng)域中的學生心理健康研究
- 小學數(shù)學新課程教學法復習題課件
- DB6103T 34-2025奶山羊選種選配技術(shù)規(guī)范
- 《社區(qū)康復》課件-第七章 腦癱患兒的社區(qū)康復實踐
- 城鄉(xiāng)環(huán)衛(wèi)一體化內(nèi)部管理制度
- 小學數(shù)學六年級解方程練習300題及答案
- 光伏十林業(yè)可行性報告
- 公路工程安全風險辨識與防控手冊
- 骨科手術(shù)糾紛案例分析課件
- 2022年廣西高考英語真題及答案(全國甲卷)
- 安全生產(chǎn)責任清單(加油站)
- 動物檢疫技術(shù)-動物檢疫的程序(動物防疫與檢疫技術(shù))
- 煤礦復工復產(chǎn)專項安全風險辨識
- DB42T 1049-2015房產(chǎn)測繪技術(shù)規(guī)程
評論
0/150
提交評論