C++面向?qū)ο蟪绦蛟O(shè)計課件_第1頁
C++面向?qū)ο蟪绦蛟O(shè)計課件_第2頁
C++面向?qū)ο蟪绦蛟O(shè)計課件_第3頁
C++面向?qū)ο蟪绦蛟O(shè)計課件_第4頁
C++面向?qū)ο蟪绦蛟O(shè)計課件_第5頁
已閱讀5頁,還剩436頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

2023-11-161C++:面向?qū)ο蟪淌皆O(shè)計2023-11-162類的誕生類(Class)是面向?qū)ο笏枷胫械囊粋€重要組成部分。如何在電腦中將“類”表達出來?在C語言中,當定義結(jié)構(gòu)體(struct):structSAMPLE{ intmember1,member2;}var1;以後,就可以使用結(jié)構(gòu)中的成員:intvar=var1.member1*var1.member2;2023-11-163將結(jié)構(gòu)體成員的使用代碼寫成一個函數(shù),得到:intcaluc(structSAMPLEvar){returnvar.member1*var.member2;}操作結(jié)構(gòu)變數(shù)類的誕生2023-11-164然後,將上面的函數(shù)放入結(jié)構(gòu)體中structSAMPLE{

intcalcu() { returnmember1*member2; } intmember1,member2;};數(shù)據(jù)成員函數(shù)成員類的誕生2023-11-165這樣的結(jié)構(gòu)體就具有了一定的屬性(member1和member2),也具有一定的行為(函數(shù)calcu),它就是“類”的雛形。該結(jié)構(gòu)體的使用方法如下:structSAMPLEvar;var.member1=var.member2=10;inttemp=var.calcu();類的誕生2023-11-1662.1類2023-11-1672.1.1類的定義classCCompanyStaff{//BEGIN

//聲明成員函數(shù)voidSetBasicSal(floatsal);//設(shè)置基本工資

//聲明(定義)數(shù)據(jù)成員intm_iStaffNum;//工作編號charm_cName[20];//姓名floatm_fRateOfAttend;//出勤率floatm_fBasicSal;//基本工資};//END多了一個函數(shù)(SetBasicSal),其他都象結(jié)構(gòu)體。struct

class2023-11-168CCompanyStaff類的定義以關(guān)鍵字class開始。其後是類名?!皗}”表示類定義的開始和結(jié)束,最終以分號結(jié)束。一般在類中只聲明成員函數(shù)的原型,而函數(shù)的實現(xiàn)(即函數(shù)體的定義)則放在類外完成?!昂瘮?shù)原型”,即只聲明函數(shù)名、參數(shù)類型和返回值類型,而不包括函數(shù)體代碼。2.1.1類的定義2023-11-169函數(shù)的定義則可在函數(shù)(SetBasicSal)聲明之後:voidCCompanyStaff::SetBasicSal(floatsal){m_fBasicSal=sal;}函數(shù)定義:函數(shù)名前多了一個類作用域運算符(CCompanyStaff::),用於標識該函數(shù)定義屬於哪一個類。2.1.1類的定義2023-11-1610對於C++語言的編程習(xí)慣:1、將類的聲明存放於“*.h”或“*.hpp”的頭檔中,每個類一個聲明檔。2、將類的定義存放於“*.cpp”檔中,與相應(yīng)的聲明檔一一對應(yīng).c

.cpp2.1.1類的定義2023-11-1611封裝成類的好處——可以實現(xiàn)數(shù)據(jù)隱藏。封裝也確定了類成員的訪問屬性。對象的封裝性2023-11-1612對象的封裝性C++語言引入面向?qū)ο笏枷?,引入類(對象)的概念之後,必然會具有一些新的特性。面向?qū)ο笏枷胫蓄悾▽ο螅┑幕咎匦灾唬悍庋b性。封裝性:直觀理解,類將屬於它的數(shù)據(jù)(成員變數(shù))和針對數(shù)據(jù)的操作(成員函數(shù))包裹在一起就是一種封裝。封裝的目的:保護類(對象)的實現(xiàn)。對封裝屬性進行細分:公有的;私有的;保護的。2023-11-1613C++語言為了實現(xiàn)面向?qū)ο蟮姆庋b,引入了三個新的“修飾”關(guān)鍵字:public

(公有的):公開的,可見的。對象成員(變數(shù)與方法)可以在對象外使用。private

(私有的):不可見的。成員只能在對象內(nèi)部使用。protected

(保護的):受到保護的。成員也只能在內(nèi)部使用。(以後再討論)C++類的成員(變數(shù)和方法)具有了各自不同的屬性。對象的封裝性2023-11-1614classCCompanyStaff{public:voidSetBasicSal(floatsal);//設(shè)置基本工資private:intm_iStaffNum;//工作編號charm_cName[20];//姓名floatm_fRateOfAttend;//出勤率floatm_fBasicSal;//基本工資};//END對象的封裝性2023-11-1615CCompanyStaffstaff;staff.SetBasicSal(600);//合法的,因為SetBasicSal是一個公開(public)的方法。staff.m_iStaffNum=100;//非法的,因為m_iStaffNum是一個私有(private)的變數(shù)。voidCCompanyStaff::SetBasicSal(floatsal){m_fBasicSal=sal;//SetBasicSal是對象的成員,所以它的定義中可以訪問m_fBasicSal私有變數(shù)。}對象的封裝性2023-11-16161、C++類定義中的缺省屬性為私有的(private)。2、每個修飾符的作用範:從一個修飾符開始,直到另外一個修飾符時結(jié)束(或類結(jié)束了)。3、C++類中的成員(變數(shù)和方法)都應(yīng)該明確地指明它們各自的屬性。對象的封裝性2023-11-16172.1.2類成員的訪問許可權(quán)封裝所實現(xiàn)的數(shù)據(jù)隱藏是面向?qū)ο蟪淌皆O(shè)計的一個關(guān)鍵特性——隱藏一個類的數(shù)據(jù)從而使其他類無法訪問。隱藏由封裝實現(xiàn),所以隱藏所實現(xiàn)的類成員的訪問控制權(quán)限也和封裝方法一一對應(yīng)。對應(yīng)於封裝,類成員有3種訪問許可權(quán):公有類型(public)、私有類型(private)保護類型(protected)。2023-11-1618類

私有

公有數(shù)據(jù)或函數(shù)數(shù)據(jù)或函數(shù)無法從類外訪問允許從類外訪問2.1.2類成員的訪問許可權(quán)2023-11-1619公有類型的成員定義了類的介面,由關(guān)鍵字public聲明,在類外只能訪問公有成員。私有類型的訪問許可權(quán)為私有的成員由關(guān)鍵字private聲明,它們只能被類本身的成員函數(shù)訪問,來自類外部的任何訪問都是非法的。保護類型的成員與私有成員類似,區(qū)別僅在於繼承過程中,保護類型的成員可以被所在類的派生類成員函數(shù)訪問;而這一點對於私有成員來說是非法的。2.1.2類成員的訪問許可權(quán)2023-11-1620類的成員函數(shù)可以訪問類的所有成員,沒有任何限制;而類對象訪問類的成員就要受到訪問控制符的限制。訪問許可權(quán)舉例:sclass2_1_demo.hsmain2_1.cpp類對象和類的成員函數(shù)對數(shù)據(jù)成員的訪問許可權(quán)不同。2.1.2類成員的訪問許可權(quán)2023-11-1621外部介面是類外訪問類中私有數(shù)據(jù)的橋樑。聲明時,類中不同訪問許可權(quán)的成員可以按任意順序出現(xiàn)。但依然涉及到一個編程習(xí)慣問題:“以數(shù)據(jù)為中心”

“以行為為中心”

國際公約。2023-11-1622建議把一個類的數(shù)據(jù)成員都聲明為私有的訪問許可權(quán)。這樣做有兩個好處:一是資訊隱藏,即實現(xiàn)封裝,把類的內(nèi)部實現(xiàn)和外部表現(xiàn)分開,讓使用者無需瞭解類的實現(xiàn)細節(jié);二是數(shù)據(jù)保護,將類的重要資訊保護起來,以免被其他程式不恰當?shù)匦薷摹?.1.2類成員的訪問許可權(quán)2023-11-16232.1.3成員函數(shù)的實現(xiàn)被隱藏的數(shù)據(jù)可以有成員函數(shù)來訪問,對數(shù)據(jù)的操作也體現(xiàn)在成員函數(shù)中:成員函數(shù)決定對象的操作行為。它是程式演算法的實現(xiàn)部分。它也是對封裝的數(shù)據(jù)進行操作的唯一途徑。它有兩種方式:類外實現(xiàn)和類內(nèi)實現(xiàn)。注:數(shù)據(jù)對成員函數(shù)無法隱藏。2023-11-16241.一般實現(xiàn)方式類外實現(xiàn)成員函數(shù)的形式如下:返回值類型類名::成員函數(shù)名(形式參數(shù)表){

函數(shù)體}例2.2企業(yè)員工類的實現(xiàn)。sclass2_2_companyStaff.hs2_2\sclass2_2_companyStaff.cpps2_2\smain2_2.cpp2023-11-16252.內(nèi)聯(lián)函數(shù)方式內(nèi)聯(lián)函數(shù)是指程式在編譯時用函數(shù)的代碼替換每一處函數(shù)調(diào)用的地方。內(nèi)聯(lián)的優(yōu)點——以空間換時間。內(nèi)聯(lián)的兩種方式:系統(tǒng)默認:代碼在類聲明中

例:sclass2_2_0_companyStaff.h函數(shù)前加關(guān)鍵字inline:inline<函數(shù)返回值類型><函數(shù)名>(<形參表>){<函數(shù)體語句>}

參見例:smain2_3.cpp。2023-11-1626內(nèi)聯(lián)和宏替換宏替換是在編譯前由預(yù)處理程式進行預(yù)處理,它只做簡單的字元替換而不涉及語法檢查。而內(nèi)聯(lián)函數(shù)是在編譯時處理的,編譯程序能識別內(nèi)聯(lián)函數(shù),對它進行語法檢查。2023-11-16272.2類與對象類(class):具有相同或相近的性質(zhì)和行為的事物集合。對象(object):theinstanceofaclass。一個類的實例,即類的性質(zhì)(變數(shù))具體化之後成為對象。一個對象是類的一種特殊情況。一個類會有很多的對象,一個對象屬於一個類。它們是一對多的關(guān)係。2023-11-1628C++中的對象(一)當C++中類的成員變數(shù)被賦與特定的值之後,它即成為一個C++的對象。CCompanyStaffstaff;//一個對象變數(shù)staff.m_iStafNum=12345;staff.m_cName=“張三”

;staff成為類CCompanyStaff的一個對象,它有了一個工作編號,對應(yīng)一個人名。當然,還會有很多其他的對象,比如staff1、staff2等等2023-11-1629C++中的對象(二)1、對象針對電腦而言,就是代碼中的一個變數(shù)。2、C++中對象變數(shù)的使用與C語言中結(jié)構(gòu)體變數(shù)的使用方法一樣。CCompanyStaffstaff1,*pstaff1,staff3[10];staff1.m_iStafNum=11111;pstaffm_iStafNum=22222;staff[0].m_iStafNum=33333;2023-11-1630C++類的對象化(一)C++中對象是類的變數(shù),但它不象變數(shù)那麼單純。C++提供一套特殊的機制實現(xiàn)類到對象的轉(zhuǎn)換。classCCompanyStaff{public:

CCompanyStaff();~CCompanyStaff();voidSetBasicSal(floatsal);//設(shè)置基本工資private:intm_iStaffNum;//工作編號};//END2023-11-1631對象的創(chuàng)建和銷毀創(chuàng)建對象時,“對象存放在何處??”需要向操作系統(tǒng)申請一定的記憶體空間用於存放新建的對象。為對象分配存儲空間主要有:靜態(tài)分配和動態(tài)分配兩種方式。2023-11-1632靜態(tài)分配:可以將對象或靜態(tài)成員存放在棧中或靜態(tài)存儲區(qū)域中。動態(tài)分配:

動態(tài)記憶體分配是指在堆(也稱自由記憶體)中分配存儲單元,即為對象動態(tài)從堆中分配記憶體。使用操作符new分配記憶體空間;使用操作符delete釋放記憶體空間。對象的創(chuàng)建和銷毀2023-11-16332.1.1構(gòu)造函數(shù)與析構(gòu)函數(shù)C++語言為了保證一個對象被初始化(類的實例化),定義了一組特殊的方法(函數(shù)),專門用於對象生成時的初始化。構(gòu)造函數(shù)(constructor)——與類名稱相同,沒有返回值。它在對象生成之時自動執(zhí)行。析構(gòu)函數(shù)(destructor)——在類名前加~作為函數(shù)名的函數(shù),沒有返回值,也沒有參數(shù)。它在對象結(jié)束時自動執(zhí)行。2023-11-1634C++要求類設(shè)置一個專門的成員函數(shù)來負責(zé)類中所有對象的初始化,這個成員函數(shù)就是構(gòu)造函數(shù)。構(gòu)造函數(shù)的作用就是在對象被創(chuàng)建時利用特定的值構(gòu)造對象,將對象初始化到一個特定的狀態(tài)。聲明一個構(gòu)造函數(shù)的語示格式如下:public:類名(<參數(shù)表>);2.1.1構(gòu)造函數(shù)與析構(gòu)函數(shù)2023-11-1635構(gòu)造函數(shù)可以由程式設(shè)計人員自己編寫。也可以由系統(tǒng)提供。例2.4構(gòu)造函數(shù)舉例。sclass2_4_companyStaff.hsmain2_4.cpp2.1.1構(gòu)造函數(shù)與析構(gòu)函數(shù)2023-11-1636重載構(gòu)造函數(shù)所謂重載構(gòu)造函數(shù),是指同一個構(gòu)造函數(shù)名,具有不同的實現(xiàn)。例2.5在員工管理系統(tǒng)中,創(chuàng)建一個對象時,還可以一次性地給對象的姓名、出勤率、基本工資等幾個數(shù)據(jù)成員都賦初值,這就需要重載構(gòu)造函數(shù)。sclass2_5_companyStaff.hsclass2_5_companyStaff.cppsmain2_5.cpp2023-11-1637需要注意一點,當構(gòu)造函數(shù)帶默認參數(shù)時,要謹防出現(xiàn)歧義。例2.6下麵這個程式存在歧義。sclass2_6.hsmain2_6.cpp當創(chuàng)建對象d2時,有二義性。2.1.1構(gòu)造函數(shù)與析構(gòu)函數(shù)2023-11-1638拷貝構(gòu)造函數(shù)拷貝構(gòu)造函數(shù)是用來複製對象的一種特殊的構(gòu)造函數(shù)。聲明拷貝構(gòu)造函數(shù)的語法格式如下:class類名{public:

類名(類名&對象名);};只有一個參數(shù)2023-11-1639例2.7通過水準座標和垂直座標來確定螢?zāi)簧系囊粋€點。sclass2_7_point.hsmain2_7.cppCPointb(a);CPointc=a;拷貝構(gòu)造函數(shù)2023-11-1640析構(gòu)函數(shù)析構(gòu)函數(shù)與構(gòu)造函數(shù)的作用幾乎正好相反,當一個對象消失時,或用delete刪除用new創(chuàng)建的對象時,系統(tǒng)都會自動調(diào)用類的析構(gòu)函數(shù),做一些清理工作。聲明一個析構(gòu)函數(shù)的語法格式如下:classDemo{public: Demo(<參數(shù)表>); ~Demo(void);}2023-11-1641析構(gòu)函數(shù)不能重載。

//析構(gòu)函數(shù)

~CCompanyStaff(void) { cout<<"對象"<<m_cName<<"消亡"<<endl; }析構(gòu)函數(shù)2023-11-1642當某對象消亡時,系統(tǒng)會自動調(diào)用該對象的析構(gòu)函數(shù)。而且調(diào)用的順序是:最後創(chuàng)建的對象最先消亡,即最先調(diào)用其析構(gòu)函數(shù);相反地,最先創(chuàng)建的對象最後消亡,即最後調(diào)用其析構(gòu)函數(shù)。 如果不顯式地定義析構(gòu)函數(shù),系統(tǒng)也會生成一個默認的析構(gòu)函數(shù),它是一個空的析構(gòu)函數(shù),不做任何事情。析構(gòu)函數(shù)2023-11-1643C++類的對象化(附)classCCompanyStaff{public:

CCompanyStaff();CCompanyStaff(intnum,char*pName);~CCompanyStaff();voidSetBasicSal(floatsal);//設(shè)置基本工資……………};//ENDCCompanyStaffstaff(12345,“張三”);2023-11-1644C++類的對象化(附)1、構(gòu)造函數(shù)與析構(gòu)函數(shù)被“隱含”調(diào)用,即不管願意與否,它們都會被“強制”地執(zhí)行。2、C++類都有缺省的構(gòu)造函數(shù),即沒有參數(shù)的構(gòu)造函數(shù)。它也是“強制”的,沒有定義每個類也有一個這樣的構(gòu)造函數(shù)。3、編程習(xí)慣:不管有用沒用,希望編程人員為每個類定義明確的構(gòu)造與析構(gòu)函數(shù)2023-11-16452.2.3對象成員的訪問可以通過對象名,也可以通過對象地址來訪問一個對象:<類名><對象名>; <對象名>.<成員名> //訪問公有數(shù)據(jù)成員<對象名>.<成員名>(<參數(shù)表>)

//訪問公有成員函數(shù)CCompanyStaffstaff1("LiHua"); staff1.SetBasicSal(4000.0);2023-11-1646<類名>*<對象指針名>;<對象指針>-><成員名> //訪問公有數(shù)據(jù)成員<對象指針>-><成員名>(<參數(shù)表>)

//訪問公有成員函數(shù)CCompanyStaff*pstaff;pstaff=newCCompanyStaff("LiuMei",0.95,3000.0);pstaff->GetName()

2.2.3對象成員的訪問2023-11-1647例2.8在員工管理系統(tǒng)中,建立兩個對象分別用兩種方式去訪問類成員。sclass2_8_companyStaff.hsclass2_8_companyStaff.cppsmain2_8.cpp2.2.3對象成員的訪問2023-11-1648對象指針:普通對象指針例2.9普通對象指針舉例。sclass2_9_objPointer.hsmain2_9.cpp

CPointerExam*pointer; pointer=&obj;

pointer->SetNum(2);對象指針在使用之前一定要初始化,為其動態(tài)分配存儲空間;使用完畢必須釋放該對象指針所代表的資源。2023-11-1649對象的this指針每個對象都擁有自己獨立的數(shù)據(jù)成員。而類中的所有對象使用相同的成員函數(shù),成員函數(shù)在內(nèi)存中只有一份。每個對象隱含了一個常量指針,稱為this指針,用於指向當前發(fā)送消息的對象,以識別當前調(diào)用成員函數(shù)的對象究竟是誰。當通過一個對象調(diào)用成員函數(shù)時,系統(tǒng)先將該對象的地址賦給this指針,成員函數(shù)在對對象的數(shù)據(jù)進行操作時,就隱含地使用了this指針。2023-11-1650CCompanyStaff(charcName[]) {

strcpy(m_cName,cName);}CCompanyStaff(charcName[],CCompanyStaff*constthis) {

strcpy(this->m_cName,cName);

}顯示指明this對象的this指針2023-11-1651CCompanyStaff(charcName[]) {

strcpy(this->m_cName,cName);

}隱含this對象的this指針2023-11-1652一般不需要顯示指出this,只有當函數(shù)需要返回當前對象自身的時候,才顯式地使用它。例2.10this指針舉例。sclass2_10_this.hsmain2_10.cpp

CSampleAdd(CSamples1,Csamples2) { this->n=s1.n+s2.n;

return(*this); }對象的this指針2023-11-1653類成員指針(1)類數(shù)據(jù)成員指針如果指針指向類數(shù)據(jù)成員的地址,則這個指針稱為類數(shù)據(jù)成員指針;<類型><類名>::*<指針名>

sclass2_11_dataPointer.hsmain2_11.cpp

intCSample::*p=&CSample::m; CSamples1; s1.*p=20;類數(shù)據(jù)成員指針只能指向公有數(shù)據(jù)成員。2023-11-1654(2)類成員函數(shù)指針如果指針指向類成員函數(shù)的地址,則稱為類成員函數(shù)指針。聲明一個類成員函數(shù)指針並為其賦值的語法格式如下:<類型>(<類名>::*<指針名>)(<參數(shù)表>)

<指針名>=<類名>::<成員函數(shù)名>;

使用指向成員函數(shù)的指針調(diào)用函數(shù)的格式如下:(*<指針名>)(<實參表>)

類成員指針2023-11-1655//主文件:smain2_12.cpp#include"sclass2_8_companyStaff.h"

//包含sclass2_8_companyStaff.h的代碼#include<iostream>usingnamespacestd;voidmain(void){ void(CCompanyStaff::*pFunc)(float);

//聲明一個類成員函數(shù)指針

CCompanyStaffstaff("LiHua");

//創(chuàng)建一個對象staff pFunc=CCompanyStaff::SetBasicSal;//指針初始化指向SetBasicSal函數(shù)

(staff.*pFunc)(3000);//相當於staff調(diào)用SetBasicSal() cout<<"員工LiHua的基本工資是"<<staff.GetBasicSal();}類成員指針2023-11-1656對象數(shù)組例2.13對象數(shù)組應(yīng)用舉例sclass2_13_fruit.hsmain2_13.cpp

CFruitd[4];

//創(chuàng)建一個對象數(shù)組,相應(yīng)調(diào)用4次構(gòu)造函數(shù)如需要建立一個對象數(shù)組,必須滿足以下條件:至少有一個構(gòu)造函數(shù)沒有參數(shù)或只帶默認參數(shù)。2023-11-1657Static靜態(tài)成員static(靜態(tài))修改類中的成員(變數(shù)和函數(shù)),表明該成員只有一個副本,與具體的對象沒有關(guān)係。static後的成員變數(shù)可以用於對象間的數(shù)據(jù)共用。static後的成員函數(shù)只能使用static成員變數(shù)。2023-11-1658static成員的使用當一個成員被static修飾之後,它的使用不再屬於各個對象,而是屬於這個類。classCCompanyStaff{public:staticvoidSetBasicSal(floatsal);

intm_iStaffNum;};//ENDCCompany::m_iStaffNum=1234;CCompany::SetBasicSal(30000);2023-11-1659靜態(tài)成員類的靜態(tài)成員擁有一塊單獨的存儲區(qū)。該類的所有對象都共用這塊靜態(tài)存儲空間這就為對象提供了一個相互通信的方法。靜態(tài)成員由關(guān)鍵字static標識。它屬於類而不屬於對象。它分為靜態(tài)數(shù)據(jù)成員和靜態(tài)成員函數(shù)。2023-11-1660聲明一個靜態(tài)數(shù)據(jù)成員的語法格式如下:static<數(shù)據(jù)類型><靜態(tài)數(shù)據(jù)成員名>靜態(tài)數(shù)據(jù)成員在使用前也要初始化,但它的初始化不能在構(gòu)造函數(shù)中進行,在類外進行。<數(shù)據(jù)類型><類名>::<靜態(tài)數(shù)據(jù)成員名>=〈初始值〉;其訪問語法格式如下:<類名>::<靜態(tài)數(shù)據(jù)成員名>靜態(tài)成員2023-11-1661sclass2_14_companyStaff.hsclass2_14_companyStaff.cppsmain2_14.cpp

staticints_iCount;intCCompanyStaff::s_iCount=1000;靜態(tài)成員2023-11-1662靜態(tài)成員函數(shù)是一種特殊的成員函數(shù),它屬於整個類,也為同類中所有對象共同擁有。只要類存在,靜態(tài)成員函數(shù)就可以使用。可以通過類名和對象名來調(diào)用。其定義語法格式如下:<類名>::<靜態(tài)成員函數(shù)名>(<參數(shù)表>)例2.15靜態(tài)成員函數(shù)舉例。sclass2_15.hsmain2_15.cpp靜態(tài)成員2023-11-1663靜態(tài)成員函數(shù)一般不訪問普通數(shù)據(jù)成員,它的作用主要是訪問和操作同類中的靜態(tài)數(shù)據(jù)成員。類的普通成員函數(shù)都擁有this指針。而靜態(tài)成員函數(shù)沒有this指針,但可以通過類名或?qū)ο竺麃韺崿F(xiàn)對它的訪問。靜態(tài)成員2023-11-1664對象封裝性的局限已經(jīng)學(xué)習(xí)過類對於成員的封裝(public,private,protected)封裝性有效地保護了對象的內(nèi)部細節(jié),使得對象的使用和對象的實現(xiàn)分開,互相不產(chǎn)生影響。同時,封裝性帶來負面影響:1、C++為實現(xiàn)對象的封裝,必然會做一些額外的工作,從而導(dǎo)致程式的效率下降。2、一個對象封裝的太好,也會讓該對象很難使用,也很難實現(xiàn)。2023-11-1665突破對象封裝C++提供了友元(friend)來解決由封裝性帶來的問題。friend關(guān)鍵字修改函數(shù)或類,因此對於一個類而言,它有友元函數(shù)或友元類。friend用於應(yīng)對編程中一些比較特殊的情況(如提高效率),絕大多數(shù)情況下不需要使用。亂使用只會使C++變成C,甚至更糟。2023-11-16665.友元關(guān)係一個類可以聲明一個友元關(guān)係,一起來共用類中的所有成員。友元如果是一個函數(shù),則稱為友元函數(shù);如果是一個類,則稱為友元類。友元函數(shù)是在類中由關(guān)鍵字friend修飾的非成員函數(shù)。友元函數(shù)可以是一個普通的函數(shù),也可以是其他類的成員函數(shù)。雖然它不是本類的成員函數(shù),但是在它的函數(shù)體中可以通過對象名訪問類的私有和保護成員。2023-11-1667例2.16友元函數(shù)與成員函數(shù)的比較。sclass2_16.hsmain2_16.cpp(例中的友元關(guān)係會發(fā)生錯誤)friendvoidFriendFunc(CSample*cp,inta)//增加一個對象指針參數(shù){ cp->i=a;//對象指針參數(shù)為i指明當前所屬對象}需要操作對象5.友元關(guān)係2023-11-1668友元函數(shù)的特點:第一、友元函數(shù)可以直接訪問該類的所有成員,但它不是該類的成員函數(shù),可以像普通函數(shù)一樣在任何地方調(diào)用。第二、友元函數(shù)不屬於任何類,因此可以放在類說明的任何位置,既可以在public區(qū),也可以在private區(qū)。第三、友元函數(shù)不需要通過對象或?qū)ο笾羔榿碚{(diào)用,可以直接調(diào)用即可。5.友元關(guān)係2023-11-1669友元類在類中可把另一個類聲明為友元類,如類B是類A的友元類,則類B中的所有成員函數(shù)都是類A的友元函數(shù),都可以訪問類A的私有和保護成員。友元類的聲明語句如下:classB;//前向引用聲明classA{ …… friendclassB;//B為A的友元類

……}5.友元關(guān)係2023-11-1670例2.17編寫一個有關(guān)棧結(jié)構(gòu)的程式,要求實現(xiàn)入棧和出棧。其中有兩個類,一個是結(jié)點類CNode,擁有結(jié)點值和指向下一結(jié)點的指針;另一個是棧類CStack,它擁有棧的頭指針。由此生成的鏈式結(jié)構(gòu)如圖2.3所示。321頭指針棧頂棧底指向下一結(jié)點的指針5.友元關(guān)係2023-11-1671sclass2_17_stack.hsclass2_17_stack.cppsmain2_17由於棧類CStack是結(jié)點類CNode的友元類,所以棧CStack類的所有成員函數(shù)都成為類CNode的友元函數(shù)。因此Push()和Pop()可以訪問結(jié)點類CNode對象的私有成員並對其進行操作。封裝是對象與外界之間一堵不透明的牆,而友元恰好在這堵牆上開了一個小孔,它以犧牲資訊隱藏、削弱封裝性為代價來實現(xiàn)數(shù)據(jù)共用。5.友元關(guān)係2023-11-16722.3C++輸入輸出流對象標準輸入輸出流:數(shù)據(jù)從程式中流入到螢?zāi)换虼牌瑱n,即輸出流;數(shù)據(jù)從鍵盤流入到程式中,即輸入流。所謂流,是從源到矢的數(shù)據(jù)流的抽象引用,具體地說,就是數(shù)據(jù)從一個對象流向另一個對象。在進行I/O操作時,首先執(zhí)行打開操作,使流和文件發(fā)生聯(lián)繫,建立聯(lián)繫後的檔才允許數(shù)據(jù)流入或流出,輸入輸出結(jié)束後,執(zhí)行關(guān)閉操作使檔與流斷開聯(lián)繫。2023-11-16732.2.1標準輸入輸出流iosistreamostreamifstreamiostreamofstreamstreambuffilebufstringbuffstreambaseistream_withassignostream_withassigniostream_withassignfstreamC++流類庫C++提供了一個流類庫,它具有兩個平行的根基類:streambuf類和ios類。2023-11-1674streambuf類主要負責(zé)緩衝區(qū)的處理,提供對緩衝區(qū)的低級操作。ios類是流基類,它及其派生類提供用戶使用流類所需的介面,支持對streambuf的緩衝。由它可以派生出輸入流類istream和輸出流類ostream等。兩個根基類以及由它們派生出的所有流類(當然包括istream類和ostream類)都被定義在名為iostream的頭檔中。因此須用“#include”編譯指令將iostream頭檔包含進來。C++流類庫2023-11-16752023-11-1676系統(tǒng)預(yù)定義的一些流:進行輸入輸出常用的標準輸入流對象cin和標準輸出流對象cout,還有未被緩衝的標準錯誤輸出cerr和被緩衝的標準錯誤輸出clog。2.預(yù)定義輸入/輸出流cin和cout2023-11-1677cin是通用輸入流類istream_withassign的對象,與標準輸入設(shè)備連接。它通過重載運算符“>>”執(zhí)行輸入操作,在流操作中將“>>”稱為提取運算符。cin從輸入流中取出數(shù)據(jù),數(shù)據(jù)從提取運算符“>>”處流進程序。2.預(yù)定義輸入/輸出流cin和cout2023-11-1678cout是通用輸出流類ostream的對象,與標準輸出設(shè)備連接。通過重載運算符“<<”執(zhí)行輸出操作,在流操作中,將“<<”稱為插入運算符。插入運算符“<<”向輸出流發(fā)送字元。實際上,位於插入運算符右側(cè)的字串被存儲在“<<”左側(cè)的流中。cout<<m<<""<<n<<endl;cout<<m;cout<<“

“;cout<<n;cout<<endl;2.預(yù)定義輸入/輸出流cin和cout2023-11-1679預(yù)定義操縱符操縱符是直接插入到流中的格式化指令,一般都定義在ios_base類中和<iomanip>頭檔中,分為帶參數(shù)和不帶參數(shù)兩類。2023-11-16802.預(yù)定義輸入/輸出流cin和cout例如:cout<<setw(5)<<n<<endl;表示設(shè)置輸出n時所占的位元組長度為5,輸出n後換行。2023-11-16812.3.2檔輸入輸出流輸入是指從磁片檔流向記憶體。輸出是指從記憶體流向磁片。

C++提供了3個檔流類:ofstream,ifstream,fstream,都定義在頭檔fstream.h中。其中fstream類以ofstream類和ifstream類為基類。ofstream類:輸出流類,用於向檔中寫入內(nèi)容;ifstream類:輸入流類,用於從檔中讀出內(nèi)容;fstream類:輸入輸出流類,用於既要讀又要寫的檔操作。2023-11-1682ofstream::ofstream(char*pFileName,intmode=ios::out,intprof=filebuf::openprot);第一個參數(shù)用於指業(yè)檔路徑及檔案名字串,第二個參數(shù)說明文件打開方式,第三個參數(shù)說明文件保護方式。例2.18給出程式的執(zhí)行結(jié)果smain2_18.cpp檔流對象構(gòu)造函數(shù)2.3.2檔輸入輸出流2023-11-16832.3.2檔輸入輸出流2023-11-16842.3.2檔輸入輸出流2023-11-1685(1)輸入流成員函數(shù)

open()close()get()getline()read()(2)輸出流成員函數(shù)put()write()2.常用輸入輸出流成員函數(shù)2023-11-16862.常用輸入輸出流成員函數(shù)例2.19下麵的程式將用戶輸入顯示到螢?zāi)簧希斎胱帜竬時輸出OK並結(jié)束。smain2_19.cpp

例2.20連續(xù)讀入一串字元,直到遇到字元q時停止,然後輸出這個字串。要求字元個數(shù)最多不超過79個。smain2_20.cpp

例2.21將英文字母及對應(yīng)的ASCⅡ值輸出到螢?zāi)簧稀main2_21.cpp

2023-11-1687C++流的應(yīng)用1、C++專門為互動式輸入與輸出定義了兩個對象:cin用於鍵盤的輸入;cout用於顯示幕的輸出。2、所有的C++流都有兩個操作符<<

和>><<:輸出(插入)操作符。流對象<<數(shù)據(jù);>>:輸入(提取)操作符。流對象>>數(shù)據(jù);2023-11-1688輸入輸出流應(yīng)用舉例例2.22員工管理系統(tǒng)中的輸入輸出sclass2_22_companyStaff.hsclass2_22_companyStaff.cppsmain2_22.cpp2023-11-1689習(xí)題課後習(xí)題、作業(yè)習(xí)題1習(xí)題2習(xí)題42023-11-1690Thanks!TheEnd2023-11-1691派生類的構(gòu)造函數(shù)與析構(gòu)函數(shù)第三章繼承132繼承方式類的繼承與派生4虛基類5聚合類6繼承應(yīng)用實例本章內(nèi)容2023-11-1692

3.1類的繼承與派生3.1.1繼承與派生實例繼承是軟體重用的一種形式。繼承是將自然界中存在的普遍和特殊關(guān)係用程式設(shè)計的方式進行分類描述;在設(shè)計新類時,允許重用某個原有類的所有特徵,並在此基礎(chǔ)上添加新類的新特徵。被重用的原有類稱為基類baseclass而新創(chuàng)建的類稱為派生類derivedclass。派生類不會影響到原有類的結(jié)構(gòu)。2023-11-1693實例:某一小型公司的實例企業(yè)員工工作編號姓名……顯示企業(yè)員工資訊計算實際發(fā)放工資……行政人員(與企業(yè)員工類相同)計算實際發(fā)放工資……經(jīng)理公司總銷售額提成比例(其餘同企業(yè)員工類)計算實際發(fā)放工資……銷售人員個人銷售額提成比例(其餘同企業(yè)員工類)計算實際發(fā)放工資……2023-11-16943.1類的繼承與派生針對該公司的情況,先設(shè)計:一個一般員工類CCompanyStaff,代表員工的共性;讓三個新類分別繼承一般員工類CCompanyStaff,然後根據(jù)各自的差異性,新類可以對繼承來的內(nèi)容進行改造。2023-11-16953.1.2派生類的定義從已有類產(chǎn)生新類的過程就是類的派生。定義語法如下:

class<派生類名><繼承方式>:<基類名1>, <繼承方式>:<基類名2>…{ <派生類成員的定義>; }3.1類的繼承與派生2023-11-1696繼承方式分為三種關(guān)鍵字:publicprivate

protected;單繼承(只有一個基類名)和多繼承;該公司情況類代碼:企業(yè)員工類相關(guān)派生類P79經(jīng)理、銷售人員、行政人員這三個派生類在聲明語句中分別指定了它們的基類CCompanyStaff,以及它們的繼承方式-public;CSaleManager類,同時繼承經(jīng)理類Cmanager和銷售人員類Csaleman;3.1類的繼承與派生2023-11-1697銷售員經(jīng)理行政主管行政人員企業(yè)員工類圖3.1.3繼承的級別增加行政主管一職,員工關(guān)係圖如下:3.1類的繼承與派生2023-11-1698用C++語言描述三個類的前向引用聲明,形成了一個“類家族”:classCCompanyStaff;//基類員工//派生類行政人員繼承員工classCAdminStaff:publicCCompanyStaff;

//派生類行政主管繼承行政人員classCForeAdmin:publicCAdminStaff;基類不受派生類變化的影響;派生類繼承了基類的全部數(shù)據(jù)成員和除了構(gòu)造函數(shù)析構(gòu)函數(shù)之外的全部成員函數(shù),但是派生類能否訪問這些成員還要受繼承方式的約束;3.1類的繼承與派生2023-11-16993.2繼承方式3.2.1公有繼承類的繼承方式有public、private和protected三種,其中private是缺省的繼承方式;公有繼承:

基類各成員的訪問許可權(quán)如果是public或protected則在派生類中保持不變而基類中的private成員對派生類不可見,如圖:2023-11-16100private基類Base圖3.3公有繼承中的訪問控制protectedpublicprivate派生類Derv:publicBaseprotectedpublicDervobjDBaseobjB3.2繼承方式2023-11-16101

例3.1一個公有繼承的例子:sclass3_1.hsclass3_1.cppsmain3_1.cpp

基類A的所有成員在派生類中的訪問控制權(quán)限都保持不變。3.2繼承方式2023-11-161023.2.2私有繼承:基類各成員無論是何種訪問許可權(quán)在派生類中一律以private的身份出現(xiàn),連派生類的對象也無法訪問,只有派生類的函數(shù)能在類內(nèi)訪問它們。若要私有繼承來的某些基類的成員函數(shù)在派生類中也能對外可見,需在派生類中對其成員公有化。

usingCAnimal::SetWeight;//在派生類中將基類的成員函數(shù)SetWeight()公有化

usingCAnimal::GetWeight;//在派生類中將基類的成員函數(shù)GetWeight()公有化例3.2私有繼承中的公有化:sclass3_2.hsmain3_2.cpp3.2繼承方式2023-11-16103私有繼承後的基類成員成為了派生類的私有成員,實際上相當於終止了基類功能的繼續(xù)派生。class<派生類名>:private<基類名>{public:

using<基類名>::<基類函數(shù)名>;//公有化

……};3.2繼承方式2023-11-161043.2.3保護繼承:

protected訪問許可權(quán): 設(shè)計基類時,在隱藏成員的同時還要允許派生類的成員能訪問到,這時protected就比private更合適;

例3.3保護許可權(quán)舉例:sclass3_3.hsmain3_3.cpp3.2繼承方式2023-11-16105使用protected修飾類成員存在的隱患,它破壞了封裝;

protected繼承;

保護繼承下基類各成員的訪問許可權(quán)(除private外)都以protected許可權(quán)出現(xiàn);比較私有繼承和保護繼承,可以看出在直接派生類中兩者的效果實際上都相同,但如果再繼續(xù)派生下去就會出現(xiàn)區(qū)別;3.2繼承方式2023-11-16106假設(shè)有A<-B<-C這樣一個繼承順序如果B私有繼承A後又派生出C那麼C就無法再間接繼承A的成員對A功能的繼承在B那兒就終止了;而如果B保護繼承A後又派生出C那麼A中的公有和保護成員在B中都是保護成員因此A的功能可以被C間接繼承;在實際開發(fā)時選擇恰當?shù)睦^承方式;3.2繼承方式2023-11-161073.2繼承方式3.2.4多繼承(多個父類):聲明多繼承的語法如下:

class<派生類名>:<繼承方式><基類名1>,<繼承方式><基類名2>,…多繼承舉例:在公司員工管理中有時會存在多繼承關(guān)係,如圖:經(jīng)理銷售部經(jīng)理銷售人員2023-11-161083.3派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)3.3.1構(gòu)造函數(shù):在創(chuàng)建派生類的對象時,系統(tǒng)執(zhí)行派生類的構(gòu)造函數(shù)而不會自動執(zhí)行基類的構(gòu)造函數(shù);在設(shè)計派生類的構(gòu)造函數(shù)時,不僅要為初始化派生類新增加的數(shù)據(jù)提供參數(shù),而且還應(yīng)為初始化基類數(shù)據(jù)成員提供參數(shù)相關(guān)語法:

<派生類名>(<形參表>):<基類名1>(<形參表1>)<基類名2>(<形參表2>)

{ <派生類新增數(shù)據(jù)成員的初始化> }2023-11-161093.3派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)派生類構(gòu)造函數(shù)的調(diào)用順序為先父輩(基類數(shù)據(jù))後自己(派生類新數(shù)據(jù));轎車具有交通工具的一般特徵,比如輪胎數(shù)目,同時又具有轎車自身的特徵,如載客人數(shù),因此轎車繼承交通工具,成為它的一個派生類。例3.4派生類構(gòu)造函數(shù)舉例:sclass3_4.hsmain3_4.cpp2023-11-161103.3派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)派生類必須定義構(gòu)造函數(shù)的兩種情況:派生類新增的數(shù)據(jù)成員需要定義構(gòu)造函數(shù)來為其初始化;基類定義了帶參數(shù)的構(gòu)造函數(shù)需要派生類為其提供參數(shù)以完成基類數(shù)據(jù)成員的初始化。2023-11-161113.3派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)3.3.2析構(gòu)函數(shù)當派生類對象消亡時,系統(tǒng)會自動調(diào)用派生類的析構(gòu)函數(shù)做一些必要的清理工作;由於在繼承過程中派生類不能繼承基類的析構(gòu)函數(shù),所以如果需要就只能在派生類中重新定義;2023-11-16112在執(zhí)行派生類的析構(gòu)函數(shù)時基類的析構(gòu)函數(shù)也將被自動調(diào)用;析構(gòu)函數(shù)調(diào)用的順序是先派生類的析構(gòu)函數(shù),然後是基類的析構(gòu)函數(shù)。例3.5派生類析構(gòu)函數(shù)舉例:

sclass3_5.hsmain3_5.cpp3.3派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)調(diào)用類A的構(gòu)造函數(shù)調(diào)用類B的構(gòu)造函數(shù)調(diào)用類B的析構(gòu)函數(shù)調(diào)用類A的析構(gòu)函數(shù)2023-11-161133.4虛基類3.4.1聲明一個虛基類

多繼承中的多義性

2023-11-161142.作用域分辨符可以通過作用域分辨符明確指定調(diào)用哪個類的介面;其語法形式如下:<派生類對象名>.<基類名>::<數(shù)據(jù)成員名>//訪問數(shù)據(jù)成員<派生類對象名>.<基類名>::<成員函數(shù)名><參數(shù)表>//訪問成員函數(shù)3.4虛基類2023-11-16115作用域分辨符舉例:Smain3_5_B.cpp基類可以將其設(shè)為虛基類,這樣它的數(shù)據(jù)成員在內(nèi)存中就只有一個副本,成員函數(shù)也只有一個映射從而解決了同名成員的唯一標識問題;3.4虛基類2023-11-161163.虛基類由virtual標識,聲明語法如下:class<派生類名>:virtual<繼承方式><基類名>;例3.6虛基類舉例:sclass3_6.hsmain3_6.cpp考慮員工管理系統(tǒng)中的多繼承關(guān)係使用虛基類來定義公司員工管理系統(tǒng)中的多繼承關(guān)係:3.4虛基類2023-11-16117//在繼承路徑“銷售經(jīng)理—>銷售人員—>員工”中將基類CCompanyStaff設(shè)為虛基類classCSaleman:virtualpublicCCompanyStaff;//在繼承路徑“銷售經(jīng)理—>經(jīng)理—>員工”中將基類CCompanyStaff設(shè)為虛基類classCManager:virtualpublicCCompanyStaff;//派生類CSaleManager成為兩條繼承路徑的交匯點classCSaleManager:publicCSaleman,publicCmanager;3.4虛基類2023-11-16118比較使用作用域分辨符和虛基類技術(shù):使用作用域分辨符時基類的成員在內(nèi)存中存在多個副本,通過指定基類名來唯一標識使用的是哪個副本,這樣可以存放不同的數(shù)據(jù)進行不同的操作;使用虛基類技術(shù)使基類的成員在內(nèi)存中只存有一個副本;3.4虛基類2023-11-161193.4.2虛基類的初始化:虛基類的初始化在語法上和處理一般基類一樣只是調(diào)用順序略有不同它遵循以下順序:1)虛基類的構(gòu)造函數(shù)在非虛基類之前調(diào)用;2)若同一層次中包含多個虛基類則按它們的聲明順序調(diào)用;3)若虛基類由非虛基類派生而來要先調(diào)用更高級別基類的構(gòu)造函數(shù)再遵循上述1和2的順序。

3.4虛基類2023-11-16120虛基類初始化順序的簡單舉例:classA;classB;classC:publicA,virtualB

{};將產(chǎn)生如下的調(diào)用次序B()

A()

C()3.4虛基類2023-11-16121較複雜的虛基類初始化舉例:

3.4虛基類2023-11-16122為了避免在不同繼承路徑中繼承來的同一成員發(fā)生多個副本的衝突可以將相應(yīng)的基類設(shè)為虛基類,見源代碼:sclass3_7.hsmain3_7.cpp運行結(jié)果:classBase1classBase2classLevel2classBase2classLevel1classLeaf3.4虛基類2023-11-161233.5聚合類3.5.1聚合類的概念設(shè)計孤立的類是較容易的,難的是正確設(shè)計基類及其派生類;一般地如果在邏輯上A是B的一部分而A與B又不屬於同一類範疇,則不允許B繼承A的功能而是要用A和其他東西組合出B;聚合(aggregation)也是實現(xiàn)程式代碼重用的另一有效手段;類的聚合,就是指在一個類中內(nèi)嵌其他類的對象作為成員的現(xiàn)象;“擁有”(hasa)關(guān)係,聚合類擁有內(nèi)嵌對象;出於資訊隱藏的考慮,常將其訪問許可權(quán)設(shè)為“私有”。2023-11-161243.5.2聚合類中的構(gòu)造函數(shù)聚合類對象在創(chuàng)建時作為其組成部件的內(nèi)嵌對象將首先被系統(tǒng)創(chuàng)建;如果一個聚合類,同時又是一個派生類,那麼它的構(gòu)造函數(shù)初始化列表還應(yīng)負責(zé)為基類構(gòu)造函數(shù)的調(diào)用提供參數(shù);當一個類既是聚合類又是派生類時的構(gòu)造函數(shù)定義形式:

<類名>::<類名><形參表><基類><形參表><內(nèi)嵌對象><形參表> { 類的初始化 }3.5聚合類2023-11-16125例3.8公司的每一個員工都擁有不同的教育背景,其中記錄著畢業(yè)學(xué)校、最高學(xué)歷等基本數(shù)據(jù)??梢詫⒔逃尘俺橄鬄橐粋€類CEducation,擁有上述數(shù)據(jù),並提供查詢數(shù)據(jù)和顯示數(shù)據(jù)等基本功能。企業(yè)員工類CCompanyStaff要使用教育背景類CEducation的功能,但是前者不能繼承後者所具有的特徵,因此可以把CCompanyStaff類處理成一個聚合類,在類中內(nèi)嵌一個Ceducation類的對象。員工管理系統(tǒng)中的聚合關(guān)係:sclass3_8_companyStaff.hsclass3_8_companyStaff.cppsmain3_8.cpp

3.5聚合類2023-11-161263.6繼承應(yīng)用實例2.6.1問題描述:該公司的員工組成很簡單,主要分成經(jīng)理,銷售部門經(jīng)理,銷售人員和行政人員等幾類;所有員工都具有姓名,工作編號,基本工資,獎金,當月出勤記錄等數(shù)據(jù),都擁有一定的教育背景;每個員工都存在錄入和顯示資訊等操作,並且需要根據(jù)考勤等實際因素來發(fā)放工資;不同類別的員工計算工資的辦法也各不相同;

例3.9公司員工管理系統(tǒng),根源程式:sclass3_9_companyStaff.hsclass3_9_companyStaff.cppsmain3_9.cpp2023-11-16127習(xí)題課後習(xí)題、作業(yè)習(xí)題1習(xí)題2習(xí)題32023-11-16128Thanks!

TheEnd2023-11-16129函數(shù)重載第四章多態(tài)性132虛函數(shù)多態(tài)性4運算符重載內(nèi)容提要2023-11-161304.1多態(tài)性基本概念及其實現(xiàn)方式多態(tài)性就是一個事物多種形態(tài),就是同一符號或者名字在不同情況下具有不同解釋的現(xiàn)象。多態(tài)性有兩種表現(xiàn)形式:一種是不同的對象在收到相同的消息時,產(chǎn)生不同的動作;另一種是同一對象收到相同的消息卻產(chǎn)生不同的函數(shù)調(diào)用。2023-11-161314.1.2多態(tài)的兩種實現(xiàn)方式兩種表現(xiàn)形式分別叫做:編譯時多態(tài)和運行時多態(tài)。(重載)編譯時多態(tài)——也叫靜態(tài)多態(tài)性,屬於早期綁定,在編譯時就實現(xiàn)了綁定,它是靜態(tài)聯(lián)編的;運行時多態(tài)——也叫動態(tài)多態(tài)性,屬於晚期綁定,在編譯時還無法確定綁定對象,只有在運行時才能夠?qū)崿F(xiàn)綁定,它是動態(tài)聯(lián)編的。通過虛函數(shù)實現(xiàn),動態(tài)4.1多態(tài)性基本概念及其實現(xiàn)方式2023-11-16132以下兩種情況不是動態(tài)聯(lián)編的:1、在基類中未使用虛函數(shù)、純虛函數(shù)。2、在基類中使用了虛函數(shù)和純虛函數(shù),但使用對象直接調(diào)用。這也不是動態(tài)聯(lián)編的。使用虛函數(shù)、純虛函數(shù),使用基類的指針或者引用。

4.1多態(tài)性基本概念及其實現(xiàn)方式2023-11-16133“綁定”——就是讓函數(shù)調(diào)用與函數(shù)體產(chǎn)生關(guān)聯(lián)。在編譯時就確定——叫“早期綁定”;在程式運行時才確定——叫“晚期綁定”。而C++的多態(tài)性在“早期綁定”和“晚期綁定”兩方面都有體現(xiàn)。4.1多態(tài)性基本概念及其實現(xiàn)方式2023-11-161344.2虛函數(shù)虛函數(shù)是在基類中使用了關(guān)鍵字virtual的成員函數(shù)。慮函數(shù)與一般函數(shù)重載的區(qū)別:1、虛函數(shù)定義在基類和派生類中,函數(shù)原型完全一致;2、函數(shù)重載在同一個類中,或者都在類外定義,函數(shù)原型必定不完全相同。虛函數(shù)——運行時多態(tài)2023-11-161354.2.1虛函數(shù)的基本概念及其定義主要通過例子程式說明其機制.4.2虛函數(shù)2023-11-16136例4_1:利用對象分別調(diào)用不同的Show()——正確調(diào)用了特定的Show()函數(shù)。s4_1\sclass4_1_student.hs4_1\sclass4_1_student.cpps4_1\smain4_1.cppCPersonoCPerson("德華劉","男"); CStudentoCStudent(20050101,"學(xué)友張","男");oCPerson.Show(); oCStudent.Show(); 4.2虛函數(shù)2023-11-16137在main()中通過“對象.成員函數(shù)”的形式調(diào)用show(),分別調(diào)用了對象自己的show()。劉德華|男張學(xué)友|男|200501014.2虛函數(shù)2023-11-16138下麵通過基類指針來調(diào)用,會有什麼結(jié)果啦?例4_2:利用基類的指針調(diào)用不同的Show()。s4_2\smain4_2.cppch4_2\sclass4_2_student.hch4_2\sclass4_2_student.cpp劉德華|男張學(xué)友|男4.2虛函數(shù)無論讓基類的指針指向基類對象還是派生類對象,系統(tǒng)都無法調(diào)用派生類對象oCStudent的Show()函數(shù)。實際調(diào)用的都是基類的Show()成員函數(shù)。

2023-11-16139通過基類的引用,引用派生類對象,會有什麼結(jié)果啦?例4_3:利用基類的引用作為參數(shù),調(diào)用不同的Show(),依然未達到目的。

s4_3\smain4_3.cppch4_3\sclass4_3_student.hch4_3\sclass4_3_student.cpp劉德華|男張學(xué)友|男4.2虛函數(shù)2023-11-16140無論引用基類對象還是派生類對象,函數(shù)內(nèi)調(diào)用的都是基類的Show()成員函數(shù)。通過基類的引用去引用派生類對象,只能看到派生類從基類中繼承而來的部分。這是由於C++的靜態(tài)聯(lián)編機制造成的。它首先將指向基類的指針與基類成員函數(shù)Show()連接在一起。這樣,不管pCPerson指向哪個對象,pCPerson->Show()調(diào)用的總是基類的成員函數(shù)Show()。4.2虛函數(shù)2023-11-16141C++提供了虛函數(shù)(virtualfunction)機制解決上述問題。通過虛函數(shù)機制,實現(xiàn)了動態(tài)聯(lián)編。一旦基類的成員函數(shù)定義為虛函數(shù),則其派生類的同名成員函數(shù)(原型一致)不管前面是否加關(guān)鍵字virtual,同樣具有虛特性,同樣是虛函數(shù)。虛函數(shù)的傳遞性4.2虛函數(shù)2023-11-16142動態(tài)聯(lián)編在多繼承中尤其有用。但虛函數(shù)機制也是有缺陷的,為了實現(xiàn)虛特性需要增加一些數(shù)據(jù)存儲和執(zhí)行指令的開銷,虛函數(shù)的使用也不是越多越好。將一個類中的所有成員函數(shù)都定義為虛函數(shù)(virtual)也是可行的,它除了會增加一些額外的開銷外,沒有其他更多的壞處,虛函數(shù)對於保證類的封裝特性是有好處的。4.2虛函數(shù)2023-11-16143虛函數(shù)的“動態(tài)聯(lián)編虛特性”必須通過基類的指針或者基類的引用來表現(xiàn)。例4_4:定義了兩個CPerson的繼承類,具有虛函數(shù)的兩個實現(xiàn)版本。s4_4\sclass4_4_student.hs4_4\sclass4_4_student.cpps4_4\smain4_4.cpp虛函數(shù)要求原型一致4.2虛函數(shù)2023-11-161441:-通過基類的引用調(diào)用具有虛特性----德華劉|男學(xué)友張|男|20050101孔老師|男|50002:-通過基類指針調(diào)用具有虛特性----德華劉|男學(xué)友張|男|20050101孔老師|男|50003:-通過對象調(diào)用則不具有虛特性----德華劉|男學(xué)友張|男|20050101孔老師|男|50004.2虛函數(shù)2023-11-16145在例4_4中,其他代碼不變,將CPerson類聲明部分的“virtualvoidShow()const;”函數(shù)定義語句去掉關(guān)鍵字virtual;改為“voidShow()const;”請問程式的運行結(jié)果會如何?4.2虛函數(shù)2023-11-161461:-通過基類引用調(diào)用(不)具有虛特性---德華劉|男學(xué)友張|男孔老師|男2:-通過基類指針調(diào)用(不)具有虛特性---德華劉|男學(xué)友張|男孔老師|男3:-通過對象調(diào)用則不具有虛特性---德華劉|男學(xué)友張|男|20050101孔老師|男|50004.2虛函數(shù)2023-11-16147虛函數(shù)的定義要遵循以下幾條重要規(guī)則:1、原型不一致,即使加上了關(guān)鍵字virtual,也不會進行滯後聯(lián)編。2、類的成員函數(shù)才能說明為虛函數(shù)。3、靜態(tài)成員函數(shù)不能是虛函數(shù),靜態(tài)成員函數(shù)是不受某個對象的限制,它屬於類。虛函數(shù)必須是成員函數(shù)4.2虛函數(shù)2023-11-161484、內(nèi)聯(lián)(inline)函數(shù)不是虛函數(shù),內(nèi)聯(lián)函數(shù)不能在運行時動態(tài)確定位置,它在編譯時採用插入函數(shù)體的方式處理。。5、構(gòu)造函數(shù)不虛函數(shù),構(gòu)造對象的時候,對象還是一片未定型的空間,只有對象構(gòu)造完成後,對象才是具體類的實例。6、析構(gòu)函數(shù)可以是虛函數(shù),而且通常將析構(gòu)函數(shù)聲明為虛函數(shù)。有兒子,則其析構(gòu)函數(shù)需要是虛函數(shù)4.2虛函數(shù)2023-11-161494.2.2虛函數(shù)與重載函數(shù)的關(guān)係1、重載函數(shù)函數(shù)名稱相同,參數(shù)不同;重載函數(shù)是在作用域相同的區(qū)域裏定義的相同名字的不同函數(shù).2、虛函數(shù)函數(shù)原型完全一致,體現(xiàn)在基類和派生類的類層次結(jié)構(gòu)中。3、重載函數(shù)可以是成員函數(shù)或友員函數(shù),而虛函數(shù)只能是成員函數(shù);4、調(diào)用重載函數(shù)以所傳遞參數(shù)序列的差別作為調(diào)用不同函數(shù)的依據(jù);虛函數(shù)則根據(jù)對象的不同調(diào)用不同類的虛函數(shù);5、重載函數(shù)在編譯時表現(xiàn)出多態(tài)性,是靜態(tài)聯(lián)編;而虛函數(shù)在運行時表現(xiàn)出多態(tài)性,是動態(tài)聯(lián)編,動態(tài)聯(lián)編是C++的精髓。4.2虛函數(shù)2023-11-161504.2.3虛函數(shù)與函數(shù)隱藏和函數(shù)覆蓋基類和派生類中的原型一致的函數(shù),如果是虛函數(shù),則稱為覆蓋;如果原型一致的函數(shù)不是虛函數(shù),就稱為隱藏。原型不一致的話,不管是否虛函數(shù),都稱為隱藏。虛函數(shù)才有可能覆蓋4.2虛函數(shù)2023-11-16151覆蓋和隱藏適用下述規(guī)則(基類和派生類):

1、完全同名,參數(shù)不同,不論是否虛函數(shù),基類的函數(shù)將被隱藏。2、如果派生類的函數(shù)與基類的函數(shù)同名,並且參數(shù)也相同,但是基類函數(shù)不是虛函數(shù)。此時,基類的函數(shù)被隱藏。3、如果派生類的函數(shù)與基類的函數(shù)同名,並且參數(shù)也相同,基類函數(shù)也是虛函數(shù)。此時,基類的函數(shù)被覆蓋了。4.2虛函數(shù)2023-11-16152另外,當基類中的虛函數(shù)和派生類中的函數(shù)原型出現(xiàn)不同時,將按照以下兩種情況處理:1、僅僅返回值類型不同,其餘均相同,系統(tǒng)會當作錯誤處理。僅僅返回值不同的函數(shù)本質(zhì)上是含糊的。2、函數(shù)原型不同,僅函數(shù)名相同。此時系統(tǒng)將認為它是重定義函數(shù),將丟失虛特性,且該函數(shù)還會隱藏基類同名函數(shù)。4.2虛函數(shù)2023-11-16153例4_5:重載、隱藏和覆蓋。

s4_5\sclass4_5_student.hs4_5\sclass4_5_student.cpps4_5\smain4_5.cpp函數(shù)名相同,原型不同的虛函數(shù)或非虛函數(shù),在派生類中都被隱藏;原型相同的虛函數(shù)在派生類中被覆蓋;原型相同的非虛函數(shù)在派生類中被隱藏。4.2虛函數(shù)2023-11-161544.2.4多重繼承中的虛函數(shù)虛函數(shù)具有傳遞性,具有虛函數(shù)的基類指針可以指向它的派生類,也可以指向它的派生類的派生類,它們都具有動態(tài)特性。為了實現(xiàn)多重繼承中虛函數(shù)的傳遞性,在派生時,需要採用public繼承方式,否則無法實現(xiàn)

溫馨提示

  • 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

提交評論