下載本文檔
版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
數(shù)據(jù)結(jié)構(gòu)計(jì)算機(jī)科學(xué)系施化吉E-mail:第二章抽象數(shù)據(jù)類(lèi)型和C++類(lèi)抽象數(shù)據(jù)類(lèi)型(AbstractDataType,ADT)是用戶(hù)在基本數(shù)據(jù)類(lèi)型基礎(chǔ)上定義和實(shí)現(xiàn)的數(shù)據(jù)類(lèi)型。一種抽象數(shù)據(jù)類(lèi)型就是定義了一種新的數(shù)據(jù)元素集合和該數(shù)據(jù)元素集合上所允許的操作集合。抽象數(shù)據(jù)類(lèi)型在更高一級(jí)的抽象程度上實(shí)現(xiàn)了信息的隱藏和封裝。C++中類(lèi)的定義體現(xiàn)了抽象數(shù)據(jù)類(lèi)型的思想。C++中對(duì)于面向?qū)ο蟪绦蛟O(shè)計(jì)的支持,核心部分就是類(lèi)的定義。2.1抽象數(shù)據(jù)類(lèi)型
2.1.1從數(shù)據(jù)類(lèi)型到抽象數(shù)據(jù)類(lèi)型數(shù)據(jù)類(lèi)型
定義:一組性質(zhì)相同的值的集合,以及定義于這個(gè)值的集合上的一組操作的總稱(chēng)。C語(yǔ)言中的基本數(shù)據(jù)類(lèi)型有
charintfloatdoublevoid
字符型整型浮點(diǎn)型雙精度型無(wú)值數(shù)據(jù)類(lèi)型規(guī)定了其值的集合中元素的取值范圍和對(duì)這些元素所能采用的操作。
例如:
整型定義了其數(shù)據(jù)集合中的元素的:
可取的值是機(jī)器所能表示的最小負(fù)整數(shù)和最大正整數(shù)之間的任何一個(gè)整數(shù)。
可用的操作有單目運(yùn)算符+、-,雙目運(yùn)算符+、-、*、/、%,關(guān)系運(yùn)算符<、<=、>、>=、==、!=和賦值運(yùn)算符=等。而抽象數(shù)據(jù)類(lèi)型:抽象數(shù)據(jù)類(lèi)型定義:是用戶(hù)自己定義和實(shí)現(xiàn)的數(shù)據(jù)類(lèi)型。是指一個(gè)數(shù)學(xué)模型以及定義在該模型上的一組操作。是用以表示應(yīng)用問(wèn)題的數(shù)據(jù)模型,由基本的數(shù)據(jù)類(lèi)型組成,并包括一組相關(guān)的服務(wù)(或稱(chēng)操作)。
抽象數(shù)據(jù)類(lèi)型類(lèi)似于在計(jì)算機(jī)機(jī)器語(yǔ)言的“位、字節(jié)和字”的基礎(chǔ)上引入“字符、整數(shù)、浮點(diǎn)數(shù)和雙精度數(shù)”等數(shù)據(jù)類(lèi)型這樣一種方法。這里,“字符、整數(shù)、浮點(diǎn)數(shù)和雙精度數(shù)”等數(shù)據(jù)類(lèi)型是對(duì)“位、字節(jié)和字”的抽象。
因?yàn)橛?jì)算機(jī)是使用二進(jìn)制定點(diǎn)數(shù)和浮點(diǎn)數(shù)來(lái)實(shí)現(xiàn)數(shù)據(jù)的存儲(chǔ)和運(yùn)算的。從計(jì)算機(jī)硬件系統(tǒng)的角度看,計(jì)算機(jī)能處理的數(shù)據(jù)類(lèi)型只包括位、字節(jié)和字。高級(jí)程序設(shè)計(jì)語(yǔ)言中引入了字符、整數(shù)、浮點(diǎn)數(shù)、雙精度數(shù)后,程序中就可以直接使用“A”,“57”,“1.3E10”等數(shù)據(jù)表示,而不必使用它們的二進(jìn)制表示。編譯程序會(huì)將這些數(shù)據(jù)值轉(zhuǎn)換成二進(jìn)制碼。
這些數(shù)據(jù)表示就是二進(jìn)制數(shù)據(jù)的抽象。
一個(gè)抽象數(shù)據(jù)類(lèi)型定義了一種新的數(shù)據(jù)元素集合和數(shù)據(jù)元素集合上所允許的操作集合。
在高級(jí)程序設(shè)計(jì)語(yǔ)言中,由基本數(shù)據(jù)類(lèi)型可以定義出更高一級(jí)的抽象數(shù)據(jù)類(lèi)型,如各種表、隊(duì)列、圖甚至窗口、管理器等。
下面以“隊(duì)列”為例,解釋抽象數(shù)據(jù)類(lèi)型。
一個(gè)隊(duì)列是由若干個(gè)元素組成的一個(gè)序列以及這個(gè)序列上的相關(guān)操作所構(gòu)成。其操作遵循的是“先到先服務(wù)”的原則。當(dāng)新的元素進(jìn)隊(duì)列:加入在隊(duì)列的尾部。
當(dāng)元素出隊(duì)列:總是取出隊(duì)列頭的元素。
隊(duì)列中的元素可以是各種不同類(lèi)型的對(duì)象。它們可以是整數(shù),也可以是字符,也可以是字符串,甚至可以是關(guān)于一個(gè)學(xué)生的記錄。不管是由什么對(duì)象組成隊(duì)列,都不影響我們對(duì)“隊(duì)列”本質(zhì)的理解?!瓣?duì)列”本質(zhì)就是“先進(jìn)先出”。
所以,可把隊(duì)列看成是一個(gè)抽象數(shù)據(jù)類(lèi)型。
注意:對(duì)于一個(gè)其數(shù)據(jù)成員完全相同的數(shù)據(jù)類(lèi)型,如果對(duì)它作不同的“限制”,即定義不同功能的一組操作,就可以形成不同的抽象數(shù)據(jù)類(lèi)型。如棧和隊(duì)列,可能都是相同的順序表結(jié)構(gòu),但“限制”不同,則具有不同的服務(wù),因此是不同的抽象數(shù)據(jù)類(lèi)型。抽象數(shù)據(jù)類(lèi)型與具體應(yīng)用無(wú)關(guān),這樣我們?cè)诰幊绦虻臅r(shí)候就可以把注意力集中在數(shù)據(jù)及其操作的理想模型上。如何描述抽象數(shù)據(jù)類(lèi)型?2.1.2抽象數(shù)據(jù)類(lèi)型描述
抽象數(shù)據(jù)類(lèi)型的特征是把使用和實(shí)現(xiàn)分離開(kāi)來(lái),實(shí)行封裝和信息隱藏。每種抽象數(shù)據(jù)類(lèi)型的描述應(yīng)包括:抽象數(shù)據(jù)類(lèi)型的名(稱(chēng))數(shù)據(jù)集合的定義每種操作的名稱(chēng),該操作的輸入、前置條件、功能、輸出和后置條件等定義。一個(gè)抽象數(shù)據(jù)類(lèi)型的描述在形式上可繁可簡(jiǎn),描述形式舉例如下:ADT
抽象數(shù)據(jù)類(lèi)型名
is
Data
數(shù)據(jù)元素集合和數(shù)據(jù)元素間的關(guān)系Operation
構(gòu)造函數(shù)數(shù)據(jù)值的初始化操作1
輸入:用戶(hù)輸入的數(shù)據(jù)值
前置條件:執(zhí)行此操作前數(shù)據(jù)所必需的狀態(tài)
動(dòng)作:對(duì)數(shù)據(jù)進(jìn)行的處理
輸出:操作后的返回值描述
后置條件:系統(tǒng)執(zhí)行操作后數(shù)據(jù)的狀態(tài)操作2
……操作3……endADT
抽象數(shù)據(jù)類(lèi)型名
例2-1
要設(shè)計(jì)一個(gè)擲骰子(zhìtóuzi
)的程序,骰子可設(shè)計(jì)成一個(gè)抽象數(shù)據(jù)類(lèi)型Dice.
其數(shù)據(jù)類(lèi)型包括:被擲骰子個(gè)數(shù)N,
擲出骰子的總點(diǎn)數(shù),
每個(gè)骰子的點(diǎn)數(shù);其操作包括:擲骰子,
返回該次投擲的骰子總點(diǎn)數(shù),
打印所擲每個(gè)骰子的點(diǎn)數(shù)。ADTDiceisData//數(shù)據(jù)集合該次投擲骰子的個(gè)數(shù)。這是一個(gè)大于或等于1的整數(shù)。
該次擲出的總點(diǎn)數(shù)。這是一個(gè)大于等于N且小于等于6N的整數(shù)。該次擲出的每個(gè)骰子的點(diǎn)數(shù)。這是一個(gè)表,表中的數(shù)值均為1到6的整數(shù)。
Operation//操作
Constructor
構(gòu)造函數(shù)確定被投擲骰子的個(gè)數(shù)
Toss//擲骰子
輸入:無(wú)前置條件:無(wú)動(dòng)作:擲骰子并計(jì)算總點(diǎn)數(shù)輸出:無(wú)后置條件:投擲的總點(diǎn)數(shù)及每個(gè)骰子的點(diǎn)數(shù)
Total//總點(diǎn)數(shù)輸入:無(wú)前置條件:無(wú)動(dòng)作:檢索該次投擲的總點(diǎn)數(shù)數(shù)據(jù)項(xiàng)輸出:返回該次投擲的總點(diǎn)數(shù)后置條件:無(wú)
DisplayToss//各骰子的點(diǎn)數(shù)輸入:無(wú)前置條件:無(wú)動(dòng)作:打印該次投擲的各骰子的點(diǎn)數(shù)輸出:無(wú)后置條件:無(wú)endADTDice本章的其他內(nèi)容,同學(xué)們?cè)谏蠈W(xué)期已經(jīng)學(xué)過(guò),這里就不再重復(fù)。但請(qǐng)同學(xué)們注意復(fù)習(xí),特別是有關(guān)模板的內(nèi)容。結(jié)束謝謝!2.2類(lèi)與對(duì)象的基本概念2.2.1類(lèi)與對(duì)象人類(lèi)是一個(gè)類(lèi)(class)。張三是人,李四是人,都是人類(lèi)的實(shí)例(instance),或稱(chēng)對(duì)象(object)。一個(gè)類(lèi)描述一類(lèi)事物以及該類(lèi)事物所應(yīng)具有的屬性,如人有身長(zhǎng)、體重、文化程度、性別、年齡等。一個(gè)對(duì)象是類(lèi)的一個(gè)實(shí)例,它具有確定的屬性值,如張三身高1.80米,體重70公斤,大學(xué)本科,男,21歲。人類(lèi)只有一個(gè),人類(lèi)的實(shí)例可以有無(wú)數(shù)個(gè)。對(duì)象是具體的,對(duì)象可以被創(chuàng)建和銷(xiāo)毀。類(lèi)是抽象的,類(lèi)是無(wú)所不在的。
例如桌子是一個(gè)類(lèi),人們不斷打造各種尺寸和各種風(fēng)格(屬性)的桌子(桌子的實(shí)例),打造桌子,又不斷毀壞桌子。年復(fù)一年,舊的去了,新的又來(lái),但桌子的概念沒(méi)變。它是一個(gè)抽象的概念。應(yīng)該稱(chēng)它為桌子類(lèi),以區(qū)別于打造的具體桌子。在計(jì)算機(jī)領(lǐng)域中,對(duì)象是指在應(yīng)用問(wèn)題中出現(xiàn)的各種實(shí)體、事件、規(guī)格說(shuō)明等。它是由一組屬性值和在這組值上的一組服務(wù)(或稱(chēng)操作)構(gòu)成的。其中,屬性值確定了對(duì)象的狀態(tài)。例如,一個(gè)顯示在計(jì)算機(jī)屏幕上的圓,作為一個(gè)幾何對(duì)象,它是由圓心坐標(biāo)、半徑長(zhǎng)度、邊線(xiàn)顏色和內(nèi)部顏色等屬性值來(lái)確定位置、大小、顏色等狀態(tài)??梢酝ㄟ^(guò)對(duì)象的服務(wù)來(lái)改變?cè)搶?duì)象的屬性值。例如,服務(wù)move(x,y),將一個(gè)圓移動(dòng)到由實(shí)數(shù)x,y所指定的圓心的新位置上。服務(wù)setRadius(r)、改變圓形的半徑。服務(wù)setEdgeColor(c),改變圓形的邊的顏色和其內(nèi)部顏色。
在面向?qū)ο蟮姆椒ㄖ?類(lèi)是具有相同操作(服務(wù))與相同數(shù)據(jù)格式(屬性)的對(duì)象的集合。類(lèi)中的每一個(gè)對(duì)象稱(chēng)為該類(lèi)的一個(gè)實(shí)例(instance)。有一個(gè)計(jì)算機(jī)電子郵件系統(tǒng),其主要工作涉及到發(fā)信人寫(xiě)信、收信人看信,還有電子郵件系統(tǒng)中信的收(receive)、發(fā)(send)及存儲(chǔ)(store)等方面。
例如,你在計(jì)算機(jī)上寫(xiě)一封信給你的同事John,那么這封信本身是一個(gè)對(duì)象。它具有一般信所有的共性。例如,有信的內(nèi)容和允許你處理的一些方法或動(dòng)作(讀信、寫(xiě)信、發(fā)信等)。信的內(nèi)容在計(jì)算機(jī)中稱(chēng)為數(shù)據(jù),而需要處理的一些方法和動(dòng)作,在計(jì)算機(jī)里則統(tǒng)稱(chēng)為“操作”,將這些信的共性匯集起來(lái)就有了對(duì)象這一概念。用計(jì)算機(jī)軟件的術(shù)語(yǔ)可描述為公式對(duì)象=數(shù)據(jù)+動(dòng)作所有的信的集合就構(gòu)成了類(lèi),信中的內(nèi)容不同(即對(duì)象的屬性值不同)。類(lèi)中的“信”都具有相同的服務(wù):發(fā)信。發(fā)送英文信和發(fā)送日文信的方式是一樣的。處理英文信和處理日文信有相同的方式,還有一些各自獨(dú)有的方式。那么,如果建立兩套平行的信件處理機(jī)制,顯然是不經(jīng)濟(jì)的。可以由“信”這個(gè)類(lèi)來(lái)定義兩個(gè)類(lèi):“英文信”和“日文信”,它們保留了“信”類(lèi)的服務(wù),并添加上各自獨(dú)立的服務(wù)。這種“保留”稱(chēng)為“繼承”。
“信”類(lèi)稱(chēng)為基類(lèi),基類(lèi)又可稱(chēng)為父類(lèi)、超類(lèi)或泛化類(lèi)。它具有一般信件的公共操作,讀、寫(xiě)、發(fā)送信?!坝⑽男拧?、“日文信”稱(chēng)為派生類(lèi),又可稱(chēng)為子類(lèi)或特化類(lèi)。它們繼承了其超類(lèi)“信”和讀、寫(xiě)、發(fā)送等操作,但同時(shí)又加上它們自己的“英文”和“日文”特定操作。類(lèi)、派生類(lèi)和實(shí)例的關(guān)系如圖2-1所示。
繼承和重用是相輔相成的兩個(gè)概念。要制造新的電冰箱,可以有兩種選擇:
一種是從草圖開(kāi)始;
另一種是對(duì)現(xiàn)有的電冰箱的型號(hào)加以改進(jìn)。也許現(xiàn)有的型號(hào)已經(jīng)令人比較滿(mǎn)意,但如果再增加兩個(gè)功能,會(huì)更加完美。
在原有的型號(hào)基礎(chǔ)上增加兩組電路,很快就制造出來(lái)新的電冰箱了,被賦予一種新的型號(hào)。這就是繼承和重用。
繼承是一種聯(lián)結(jié)類(lèi)的層次模型,并且允許和鼓勵(lì)類(lèi)的重用。
層次結(jié)構(gòu)的上層(或祖先類(lèi))最具有通用性。下層部分,即后代具有特殊性。
類(lèi)可以從它的祖先那里繼承方法和實(shí)例變量(即對(duì)象中可訪(fǎng)問(wèn)的數(shù)據(jù)),也可以修改或增加新的方法使之更符合特殊的需要。
2.2.2消息與合作一個(gè)對(duì)象內(nèi)具有過(guò)程和數(shù)據(jù)。外部的用戶(hù)或?qū)ο髮?duì)對(duì)象提出的請(qǐng)求,可以稱(chēng)為對(duì)該對(duì)象發(fā)送消息。在電子郵件系統(tǒng)的例中,對(duì)象“信”具有讀信、寫(xiě)信或發(fā)信等操作,是由系統(tǒng)設(shè)計(jì)者開(kāi)發(fā)并由對(duì)象“信”提供給用戶(hù)的,用戶(hù)可以發(fā)送一個(gè)消息(或稱(chēng)為請(qǐng)求)來(lái)請(qǐng)求所需的服務(wù)。在面向?qū)ο蟮姆椒ㄖ?另一個(gè)經(jīng)常用的概念就是“合作”。
合作是指兩個(gè)對(duì)象之間共同承擔(dān)職責(zé)來(lái)達(dá)到某一目標(biāo)。當(dāng)你告訴對(duì)象“信”,你想把它發(fā)送給John時(shí),你此時(shí)的作用就是一個(gè)客戶(hù)。對(duì)象“信”在這里相當(dāng)于一個(gè)服務(wù)器。它提供給你一個(gè)服務(wù)。
你還可以要求別的服務(wù),如讀、寫(xiě)信等。很多人用客戶(hù)/服務(wù)器模型來(lái)描述面向?qū)ο竽P?。在這個(gè)模型中,各個(gè)對(duì)象具有完成不同任務(wù)的職責(zé),客戶(hù)對(duì)象可以通過(guò)服務(wù)器對(duì)象來(lái)完成一些任務(wù)。這里把兩個(gè)對(duì)象共同承擔(dān)職責(zé)稱(chēng)為“合作”。2.2.3多態(tài)性多態(tài)性機(jī)制是指允許不同類(lèi)的對(duì)象對(duì)同一消息作出響應(yīng)。以前面提到的電子郵件系統(tǒng)為例,現(xiàn)有局域網(wǎng)類(lèi)對(duì)象LAN和寬域網(wǎng)類(lèi)對(duì)象WAN,這兩類(lèi)對(duì)象均可對(duì)來(lái)自對(duì)象“信”的同一消息“發(fā)送給John”作出響應(yīng)。即對(duì)同一個(gè)“發(fā)送給John”操作,可以有不同的實(shí)現(xiàn)方法。可以通過(guò)TCP-IP協(xié)議來(lái)找到John,也可通過(guò)X.25協(xié)議來(lái)找到John,這是在系統(tǒng)運(yùn)行時(shí)由系統(tǒng)決定的。這種動(dòng)態(tài)決定實(shí)現(xiàn)方法的機(jī)制稱(chēng)為動(dòng)態(tài)聯(lián)編(dynamicbinding)。
一個(gè)多態(tài)性的例子:
學(xué)生類(lèi)應(yīng)該有一個(gè)計(jì)算成績(jī)的操作。大學(xué)生繼承了中學(xué)生。對(duì)于中學(xué)生,計(jì)算成績(jī)的操作是對(duì)語(yǔ)文、數(shù)學(xué)、英語(yǔ)等課程的計(jì)算,而對(duì)于后繼的大學(xué)生,計(jì)算成績(jī)的操作是對(duì)高等數(shù)學(xué)、計(jì)算機(jī)、普通物理等課程的計(jì)算。
多態(tài)性引用靜態(tài)類(lèi)型和動(dòng)態(tài)類(lèi)型。多態(tài)引用的動(dòng)態(tài)類(lèi)型可以在程序執(zhí)行期間在實(shí)例之間進(jìn)行變化。
在強(qiáng)類(lèi)型面向?qū)ο蟓h(huán)境中,運(yùn)行時(shí)系統(tǒng)保持所有多態(tài)引用自動(dòng)地和它們的動(dòng)態(tài)類(lèi)型相聯(lián)結(jié)。
靜態(tài)類(lèi)型是在程序上下文中由實(shí)體說(shuō)明決定的。在編譯時(shí),系統(tǒng)知道并且決定對(duì)象在運(yùn)行時(shí)可接受的有效類(lèi)型。這一決定是通過(guò)分析繼承圖實(shí)現(xiàn)的。
2.3面向?qū)ο蟮某绦蛟O(shè)計(jì)方法
傳統(tǒng)的程序設(shè)計(jì)技術(shù)采用的是算法分解。算法分解就是功能分解,該方法將軟件看成一個(gè)處理過(guò)程,將該過(guò)程分解成若干個(gè)步驟的模塊。一般都是在項(xiàng)目被分解成了功能模塊后,再來(lái)考慮數(shù)據(jù)結(jié)構(gòu)。
面向?qū)ο蟮某绦蛟O(shè)計(jì)技術(shù)建立在對(duì)象分解的基礎(chǔ)上,以類(lèi)設(shè)計(jì)為核心。面向?qū)ο蠓纸鈱④浖闯捎辛己枚x的對(duì)象組成的集合。這些對(duì)象是應(yīng)用領(lǐng)域中實(shí)體的模型化體現(xiàn)。這些對(duì)象以及對(duì)象之間的相互作用構(gòu)成了一個(gè)軟件系統(tǒng)。當(dāng)系統(tǒng)已被分解成為若干個(gè)對(duì)象之后,再去考慮功能的分解。
面向?qū)ο蠓纸庾钪饕膬?yōu)點(diǎn)在于它增進(jìn)了軟件的可重用性。面向?qū)ο蠓纸馔嫦蛩惴ǚ纸庀啾容^更直觀(guān)。
程序設(shè)計(jì)階段應(yīng)給出所有對(duì)象的描述,這是構(gòu)成程序的主要部分。同時(shí),設(shè)計(jì)階段也描述對(duì)象間相互作用的控制。對(duì)象設(shè)計(jì)階段明確所有在程序中將要用到的對(duì)象,并給出每個(gè)類(lèi)的定義,再設(shè)計(jì)出一些程序模塊對(duì)類(lèi)進(jìn)行測(cè)試。類(lèi)可以獨(dú)立于系統(tǒng)之外測(cè)試,這是面向?qū)ο蟪绦蛟O(shè)計(jì)的一大特色。
處理控制設(shè)計(jì)階段完成程序的框架設(shè)計(jì),它使用自頂向下方法創(chuàng)建主程序和子程序來(lái)控制對(duì)象間的相互作用。
2.4
C++類(lèi)與對(duì)象C++對(duì)于面向?qū)ο蟪绦蛟O(shè)計(jì)的支持,核心就是類(lèi)的定義。類(lèi)由多個(gè)存放數(shù)據(jù)值的成員和加工數(shù)據(jù)的運(yùn)算組成。這些運(yùn)算稱(chēng)為成員函數(shù),又稱(chēng)為方法。成員函數(shù)用來(lái)響應(yīng)發(fā)送給對(duì)象的消息。消息就是對(duì)成員函數(shù)的調(diào)用。定義了一個(gè)類(lèi)以后,就可以用該類(lèi)的名字來(lái)聲明該類(lèi)的對(duì)象。
類(lèi)可以分為兩個(gè)部分:
公共(public)部分描述用戶(hù)使用類(lèi)的界面。對(duì)于在public域中聲明的數(shù)據(jù)成員和成員函數(shù),程序中其它類(lèi)的對(duì)象或操作都能請(qǐng)求該類(lèi)的對(duì)象調(diào)用它們,該界面使用戶(hù)不必了解對(duì)象的內(nèi)部細(xì)節(jié)而使用對(duì)象。
私有(private)部分由幫助實(shí)現(xiàn)數(shù)據(jù)抽象的數(shù)據(jù)和內(nèi)部操作組成。私有部分包括private域和protected域,這兩個(gè)域中聲明的數(shù)據(jù)成員和成員函數(shù)只能由該類(lèi)的對(duì)象和成員函數(shù)以及聲明為友元(friend)的函數(shù)或類(lèi)的對(duì)象訪(fǎng)問(wèn)。
例2-2
一個(gè)定義類(lèi)、使用類(lèi)的例子//TIME1.H//類(lèi)Time的聲明//成員函數(shù)在TIME1.cpp中定義#ifndefTIME1_H#defineTIME1_H//抽象數(shù)據(jù)類(lèi)型Time的定義classTime{public:Time();//默認(rèn)構(gòu)造函數(shù)voidsetTime(int,int,int);//設(shè)置時(shí)、分、秒voidprintStandardTime();//打印標(biāo)準(zhǔn)格式的時(shí)間private:inthour;//0-23intminute;//0-59intsecond;//0-59};#endif//TIME1.cpp//類(lèi)Time的成員函數(shù)的定義#include<iostream.h>#include“TIME1.H”/*類(lèi)Time的構(gòu)造函數(shù)把每一個(gè)數(shù)據(jù)成員初始化為零,從而保證所有的類(lèi)Time的對(duì)象具有穩(wěn)定的初始狀態(tài)*/Time::Time(){hour=minute=second=0;}/*設(shè)定一個(gè)新的時(shí)間值,檢查數(shù)據(jù)值的合法性,將非法值設(shè)置為零*/voidTime::setTime(inth,intm,ints){Hour=(h>=0&&h<24)?h:0;Minute=(m>=0&&m<60)?m:0;Second=(s>=0&&s<60)?s:0;}//按標(biāo)準(zhǔn)格式輸出時(shí)間voidtime::printStandardTime(){cout<<((hour==0||hour==12)?12:hour%12)<<“:“<<(minute<10?“0“:““)<<minute<<“:“<<(second<10?“0“:““)<<second<<(hour<12?“AM“:“PM“);}//Example2-2.cpp//使用類(lèi)Time的程序//注:與文件TIME.cpp一起編譯#include<iostream.h>#include“TIME1.h//測(cè)試類(lèi)Time的程序main(){Timet;//類(lèi)Time的實(shí)例對(duì)象tcout<<“Theinitialstandardtimeis“;t.printStandardTime();t.setTime(14,25,9);cout<<“\nstandardtimeaftersetTimeis“;t.printStandardTime();t.setTime(70,70,70);//試圖設(shè)定非法值cout<<”\nAfterattemptinginvalidsettingsstandardtimeis”;t.printStandardTime();cout<<endl;return0;}2.5構(gòu)造函數(shù)和析構(gòu)函數(shù)
構(gòu)造函數(shù)是在創(chuàng)建類(lèi)的對(duì)象時(shí)自動(dòng)調(diào)用的。類(lèi)的數(shù)據(jù)成員不能在定義類(lèi)的時(shí)候初始化,而必須在類(lèi)的構(gòu)造函數(shù)中初始化,或者在建立類(lèi)的對(duì)象后再設(shè)置它們的值。
構(gòu)造函數(shù)不能自動(dòng)返回值類(lèi)型和返回值??梢灾剌d構(gòu)造函數(shù)以便用各種方法初始化類(lèi)的對(duì)象。構(gòu)造函數(shù)可以使用默認(rèn)參數(shù)。
給構(gòu)造函數(shù)提供默認(rèn)參數(shù)的好處是:即使在調(diào)用構(gòu)造函數(shù)的時(shí)候沒(méi)有提供參數(shù)值,也會(huì)確保按照默認(rèn)的參數(shù)值對(duì)對(duì)象進(jìn)行初始化。
當(dāng)一個(gè)構(gòu)造函數(shù)所有參數(shù)都是默認(rèn)參數(shù)時(shí),該構(gòu)造函數(shù)是默認(rèn)的構(gòu)造函數(shù),也就是說(shuō),在調(diào)用這樣的構(gòu)造函數(shù)時(shí)可以不提供任何參數(shù)。例2-3初始化類(lèi)Time的對(duì)象
//TIME2.H//類(lèi)Time的聲明//成員函數(shù)在TIME2.cpp中定義#ifndefTIME2_H#defineTIME2_HclassTime{public:Time(int=0,int=0,int=0);//默認(rèn)構(gòu)造函數(shù)
voidSetTime(int,int,int);voidprintStandardTime();private:inthour;intminute;intsecond;};#endif
//TIME2.cpp//類(lèi)Time的成員函數(shù)的定義#include<iostream.h>//初始化私有數(shù)據(jù)成員的構(gòu)造函數(shù)//默認(rèn)值是0Time::Time(inthr,intmin,intsec){hour=(hr>=0&&hr<24)?hr:0;minute=(min>=0&&min<60)?min:0;second=(sec>=0&&sec<60)?sec:0;}voidTime::SetTime(inth,intm,ints){hour=(h>=0&&h<24)?h:0;minute=(m>=0&&m<60)?m:0;second=(s>=0&&s<60)?s:0;}voidTime::printStandardTime(){cout<<((hour==0||hour==12)?12:hour%12)<<“:“<<(minute<10?“0“:““)<<minute<<“:“<<(second<10?“0“:““)<<second<<(hour<12?“AM“:“PM“);}#include<iostream.h>#include“TIME2.H”main(){Timet1,t2(2),t3(15,30),t4(12,20,40),t5(28,70,99);cout<<“Constructedwithallargumentsdefaulted:\n“;t1.printStandardTime();cout<<“\nhourspecified;minuteandseconddefaulted:\n“;t2.printStandardTime();cout<<“\nhourandminutespecified;minutedefaulted:\n“;t3.printStandardTime();cout<<“\nhour,minuteandsecondspecified:\n“;t4.printStandardTime();cout<<“\nallinvalidvaluesspecified:\n“;t5.printStandardTime();cout<<endl;return0;}輸出結(jié)果:Constructedwithallargumentsdefaulted12:00:00AMhourspecified;minuteandseconddefaulted:2:00:00AMhourandminutespecified;minutedefaulted:3:30:00PMhour,minuteandsecondspecified:12:20:40PMallinvalidvaluesspecified:12:00:00AM
如果沒(méi)有為類(lèi)定義構(gòu)造函數(shù),那么編譯器就會(huì)為該類(lèi)添加一個(gè)默認(rèn)構(gòu)造函數(shù)。默認(rèn)構(gòu)造函數(shù)并不作任何初始化工作,所以在建立該類(lèi)的對(duì)象時(shí)不能保證有一個(gè)確定的初始狀態(tài)。
析構(gòu)函數(shù)是類(lèi)的一個(gè)特殊的成員函數(shù),析構(gòu)函數(shù)的標(biāo)志是在類(lèi)的名字的前面加上字符“”。
析構(gòu)函數(shù)是構(gòu)造函數(shù)的反向操作。當(dāng)撤銷(xiāo)一個(gè)類(lèi)的對(duì)象時(shí),該類(lèi)的析構(gòu)函數(shù)就自動(dòng)被調(diào)用,在系統(tǒng)回收對(duì)象所占用的內(nèi)存空間之前先做的一些清理工作。析構(gòu)函數(shù)沒(méi)有參數(shù)和返回值。
一個(gè)類(lèi)只能有一個(gè)析構(gòu)函數(shù),重載析構(gòu)函數(shù)是不允許的。當(dāng)類(lèi)的對(duì)象包含動(dòng)態(tài)分配的內(nèi)存時(shí),為類(lèi)提供析構(gòu)函數(shù)是合適的。
析構(gòu)函數(shù)和構(gòu)造函數(shù)通常是被自動(dòng)調(diào)用的,其調(diào)用順序取決于建立和撤銷(xiāo)對(duì)象的順序。一般來(lái)說(shuō),調(diào)用析構(gòu)函數(shù)的順序與調(diào)用構(gòu)造函數(shù)的順序相反。但是,對(duì)象的作用域會(huì)改變析構(gòu)函數(shù)的順序。對(duì)聲明為全局的對(duì)象來(lái)說(shuō),其構(gòu)造函數(shù)在聲明該對(duì)象的時(shí)候調(diào)用,
相應(yīng)的析構(gòu)函數(shù)在程序退出該對(duì)象的作用域的時(shí)候被調(diào)用。靜態(tài)局部對(duì)象的構(gòu)造函數(shù)只在聲明該對(duì)象的時(shí)候調(diào)用一次,相應(yīng)的析構(gòu)函數(shù)在程序終止的時(shí)候被調(diào)用。
例2-4
類(lèi)ConstructAndDestruct
//CONSTRUCT.H//類(lèi)ConstructAndDestruct的定義//成員函數(shù)在CONSTRUCT.CPP中定義#ifndefCONSTRUCT_H#defineCONSTRUCT_HclassConstructAndDestruct{public:ConstructAndDestruct(int);//構(gòu)造函數(shù)~ConstructAndDestruct();//析構(gòu)函數(shù)private:intdata;};#endif(接下頁(yè))//CONSTRUCT.CPP//類(lèi)ConstructAndDestruct的成員函數(shù)的定義#include<iostream.h>#include“construct.h“ConstructAndDestruct::ConstructAndDestruct(intvalue){data=value;cout<<“Object“<<data<<“constructor“;}ConstructAndDestruct::~ConstructAndDestruct(){cout<<“Object“<<data<<“destructor“<<endl;}//Example2-4.CPP//演示構(gòu)造函數(shù)和析構(gòu)函數(shù)的調(diào)用順序#include<iostream.h>#include“construct.h“voidconstruct(void);//函數(shù)原型ConstructAndDestructfirst(1);//全局對(duì)象(接下頁(yè))main(){
cout<<“(globalconstructbeforemain)\n“;ConstructAndDestructsecond(2);//局部對(duì)象cout<<“(localautomaticinmain)\n“;
staticConstructAndDestructthird(3);//局部對(duì)象
cout<<“(localstaticinmain)\n“;
construct();//調(diào)用建立對(duì)象的函數(shù)
ConstructAndDestructfourth(4);//局部對(duì)象
cout<<“(localautomaticinmain)\n“;
return0;}(接下頁(yè))//建立函數(shù)的對(duì)象voidconstruct(void){ConstructAndDestructfifth(5);cout<<“(localautomaticinconstruct)\n“;ConstructAndDestructsixth(6);cout<<“(localstaticinconstruct)\n“;ConstructAndDestructseventh(7);cout<<“(localautomaticinconstruct)\n“;}輸出結(jié)果:Object1constructor(globalconstructbeforemain)Object2constructor(localautomaticinmain)Object3constructor(localstaticinmain)Object5constructor(localautomaticinconstruct)Object6constructor(localstaticinconstruct)Object7constructor(localautomaticinconstruct)
(接下頁(yè))Object7destructorObject6destructorObject5destructorObject4constructor(localautomaticinmain)Object4destructorObject2destructorObject3destructorObject1destructor2.6工具函數(shù)
并不是所有的成員函數(shù)都要設(shè)定成公有的。一些成員函數(shù)可以是私有的,它們用作其它成員函數(shù)的工具函數(shù)。成員函數(shù)可以分為許多種:
讀取和返回私有數(shù)據(jù)成員值的函數(shù);設(shè)定私有數(shù)據(jù)成員值的函數(shù);實(shí)現(xiàn)類(lèi)的特點(diǎn)的函數(shù);完成類(lèi)的各種基本操作的函數(shù)(如初始化類(lèi)的對(duì)象、給類(lèi)的對(duì)象賦值、實(shí)現(xiàn)類(lèi)與內(nèi)部類(lèi)型或與其它類(lèi)之間的轉(zhuǎn)換,處理類(lèi)的對(duì)象所占用的內(nèi)存等等)。訪(fǎng)問(wèn)函數(shù)可以讀取和顯示數(shù)據(jù)。訪(fǎng)問(wèn)函數(shù)還經(jīng)常用來(lái)測(cè)試條件的真假,這類(lèi)函數(shù)通常叫做判斷函數(shù)。函數(shù)IsEmpty是一個(gè)判斷函數(shù),它用于諸如鏈表、堆棧或隊(duì)列等等的包容器類(lèi)。IsFull判斷函數(shù)用于測(cè)試包容器對(duì)象中是否還有剩余的空間。例2-5的程序演示了工具函數(shù)的使用。工具函數(shù)不是類(lèi)的接口,而是類(lèi)的私有成員,用于支持類(lèi)的公有成員函數(shù)的操作。類(lèi)的客戶(hù)不能直接使用工具函數(shù)。
例2-5
演示工具函數(shù)的使用
//SALESP.H//類(lèi)SalesPerson的定義//成員函數(shù)在SALESP.CPP中定義
#ifndefSALESP_H#defineSALESP_HclassSalesPerson{public:SalesPerson();//構(gòu)造函數(shù)
voidsetSales();//由用戶(hù)提供售貨額
voidprintAnnualSales();private:
doublesales[13];//12個(gè)月的售貨額
doubletotalAnnualSales();//工具函數(shù)};#endif//SALESP.CPP//類(lèi)SalesPerson的成員函數(shù)#include<iostream.h>#include<iomanip.h>#include“salesp.h“//構(gòu)造函數(shù)對(duì)數(shù)組的初始化SalesPerson::SalesPerson(){for(inti=0;i<=12;i++)sales[i]=0.0;}//設(shè)置十二個(gè)月銷(xiāo)售額的函數(shù)voidSalesPerson::setSales(){inti; for(inti=1;I<=12;I++){
cout<<“Entersalesamountformonth“<<i<<“:“;
cin>>sales[i];
}}//Example2-5.CPP//演示工具函數(shù)的使用//與SALESP.CPP一起編譯#include“salesp.h“main(){SalesPersons;//建立類(lèi)SalesPerson的對(duì)象ss.setSales();s.printAnnualSales();
return0;}輸出結(jié)果:Entersalesamountformonth1:5314.76Entersalesamountformonth2:4292.38Entersalesamountformonth3:4589.83Entersalesamountformonth4:5534.03
Entersalesamountformonth5:4376.34Entersalesamountformonth6:5698.45Entersalesamountformonth7:4439.22Entersalesamountformonth8:5893.57Entersalesamountformonth9:4909.67Entersalesamountformonth10:5123.45Entersalesamountformonth11:4024.97Entersalesamountformonth12:5923.92Totalannualsalesare:$60120.592.7繼承
繼承是軟件重用的一種形式。實(shí)現(xiàn)的方法就是從現(xiàn)有的類(lèi)(基類(lèi))建立新的類(lèi)(派生類(lèi))。新類(lèi)繼承了現(xiàn)有類(lèi)的屬性和行為,并且為了使新類(lèi)具有自己所需的功能,新類(lèi)還可以對(duì)這些屬性和行為進(jìn)行修飾。軟件重用縮短了程序的開(kāi)發(fā)時(shí)間,使開(kāi)發(fā)人員可以重用已經(jīng)測(cè)試和調(diào)試好了的高質(zhì)量的軟件。在建立一個(gè)派生類(lèi)時(shí),程序員可以讓其繼承基類(lèi)的數(shù)據(jù)成員和成員函數(shù),而不必重新編寫(xiě)新的數(shù)據(jù)成員和成員函數(shù),派生類(lèi)本身也可能成為未來(lái)派生類(lèi)的基類(lèi)。
用類(lèi)似的方法處理基類(lèi)對(duì)象和派生類(lèi)對(duì)象是可能的。基類(lèi)的屬性和行為表述了基類(lèi)對(duì)象和派生類(lèi)對(duì)象的共性。從基類(lèi)公有派生出來(lái)的所有對(duì)象都可以作為基類(lèi)對(duì)象處理。
例2–6
類(lèi)point的定義和派生類(lèi)circle//POINT.H//類(lèi)point的定義#ifndefPOINT_H#definePOINT_H#include<iostream.h>classPoint{friendostream&operator<<(ostream&,constpoint&);public:Point(float=0,float=0);//默認(rèn)的構(gòu)造函數(shù)voidsetPoint(float,float);//設(shè)置坐標(biāo)值floatgetX()const{returnx;}floatgetY()const{returny;}protected://允許派生類(lèi)訪(fǎng)問(wèn)
floatx,y;//點(diǎn)(類(lèi)Point的對(duì)象)的x和y坐標(biāo)};#endif
//POINT.CPP//定義類(lèi)Point的成員函數(shù)#include<iostream.h>#include"point.h"http://類(lèi)Point的構(gòu)造函數(shù)Point::Point(floata,floatb){x=a;y=b;}//設(shè)置點(diǎn)的x和y坐標(biāo)voidPoint::setPoint(floata,floatb){x=a;y=b;}//用重載的流插入運(yùn)算符輸出點(diǎn)的坐標(biāo)ostream&operator<<(ostream&output,constPoint&p){ output<<'['<<p.x<<","<<p.y<<']';
returnoutput;//使得能夠連續(xù)調(diào)用}//CIRCLE.H//類(lèi)Circle的定義#ifndefCIRCLE_H#defineCIRCLE_H#include<iostream.h>#include<iomanimp.h>#include"point.h"classCircle:publicPoint{friendostream&operator<<(ostream&,constCircle&);public://默認(rèn)的構(gòu)造函數(shù)Circle(floatr=0.0,floatx=0,floaty=0);voidsetRadius(float);//設(shè)置半徑值floatgetRadius()const;//返回半徑值floatarea()const;//計(jì)算圓的面積protected:
floatradius;};#endif
//CIRCLE.CPP//定義類(lèi)Circle的成員函數(shù)#include"circle.h“//先用成員初始化值調(diào)用類(lèi)Point的構(gòu)造函數(shù),//然后再調(diào)用類(lèi)Circle的構(gòu)造函數(shù)初始化半徑值Circle::Circle(floatr,floata,floatb):Point(a,b)//調(diào)用基類(lèi)的構(gòu)造函數(shù){radius=r;}//設(shè)置圓的半徑值floatCircle::getRadius()const{returnradius;}
//計(jì)算圓的面積floatCircle::area()const{return3.14159*radius*radius;}
//以Center=[x,y];Radius=#.##形式輸出一個(gè)圓ostream&operator<<(ostream&output,constCircle&c){ output<<"Center=["<<c.x<<","<<c.y <<"];Radius="<<setiosflags(ios::showpoint) <<setprecision(2)<<c.radius;
returnoutput;//使得能夠連續(xù)調(diào)用}CIRCLE-1.CPP//把基類(lèi)指針強(qiáng)制轉(zhuǎn)換為派生類(lèi)指針#include<iostream.h>#include<iomanip.h>#include"point.h"#include"circle.h“intmain(){Point*pointPtr,p(3.5,5.3);Circle*circlePtr,c(2.7,1.2,8.9);
cout<<“Pointp:”<<p<<“\nCirclec:”<<c<<endl;/*Circle的對(duì)象還是作為Circle對(duì)象處理,但是用了一些類(lèi)型轉(zhuǎn)換*/pointPtr=&c;//把Circle對(duì)象的地址賦給pointPtrcirclePtr=(Circle*)pointPtr;//把基類(lèi)指針轉(zhuǎn)換為派生類(lèi)指針
cout<<"\nAreaofc(viacirclePtr):" <<circlePtr->area()<<endl;//危險(xiǎn):把Point的對(duì)象作為Circle對(duì)象處理
pointPtr=&p;//把Point對(duì)象的地址賦給pointPtrcirclePtr=(Circle*)pointPtr;//把基類(lèi)指針轉(zhuǎn)換為派生類(lèi)指針
cout<<"/nRadiusofobjectcirclePtrpointsto:"<<circlePtr->getRadius()<<endl;
return0;}
輸出結(jié)果:Pointp:[3.5,5.3]Circlec:Center=[1.2,8.9];Radius=2.70Areaofc(viacirclePtr):23RadiusofobjectcirclePtrpointsto:9.5e-039
從一個(gè)基類(lèi)派生一個(gè)類(lèi)時(shí),繼承基類(lèi)的方式除了公有繼承以外,還有受保護(hù)(protected)繼承和私有繼承(private),后兩種繼承不常用。
派生類(lèi)不繼承基類(lèi)的構(gòu)造函數(shù)和賦值運(yùn)算符,但是派生類(lèi)的構(gòu)造函數(shù)和賦值運(yùn)算符能調(diào)用基類(lèi)的構(gòu)造函數(shù)和賦值運(yùn)算符。派生類(lèi)的構(gòu)造函數(shù)總是先調(diào)用其基類(lèi)構(gòu)造函數(shù)來(lái)初始化類(lèi)中的基類(lèi)成員。
如果省略了派生類(lèi)的構(gòu)造函數(shù),那么就由默認(rèn)構(gòu)造函數(shù)調(diào)用基類(lèi)的構(gòu)造函數(shù)。析構(gòu)函數(shù)的調(diào)用順序和調(diào)用構(gòu)造函數(shù)的順序相反,因此派生類(lèi)的析構(gòu)函數(shù)在基類(lèi)析構(gòu)函數(shù)之前調(diào)用。
2.8this指針的使用
在C++中,每個(gè)對(duì)象都有一個(gè)指向自身的指針。該指針?lè)Q為this指針。在引用對(duì)象內(nèi)部的成員時(shí),this指針是一個(gè)隱含的參數(shù),即不需顯式寫(xiě)出它,就可直接訪(fǎng)問(wèn)對(duì)象內(nèi)部的成員。當(dāng)然,也可以明確地使用this指針。
每一個(gè)對(duì)象都可以通過(guò)使用this指針來(lái)確定其自身的地址。這就是為什么當(dāng)成員函數(shù)引用該類(lèi)的一個(gè)特定對(duì)象的另一個(gè)成員時(shí),C++能保證該函數(shù)能正確地引用了該對(duì)象。例2-7
用this指針引用對(duì)象的成員
//Example2-7.cpp#include<iostream.h>classUsingThis{public:UsingThis(int=99);
voidprint()const;private:inty;};UsingThis::UsingThis(inta){y=a;}//構(gòu)造函數(shù)voidUsingThis::print()const{
cout<<”y=”<<y<<”\nthis->y=”<<this->y<<”\n(*this).y=”<<(*this).y<<’\n’;}main(){UsingThisu(88);u.print();return0;}輸出結(jié)果:y=88this->y=88(*this).y=88
2.9虛函數(shù)、多態(tài)性以及動(dòng)態(tài)聯(lián)編2.9.1虛函數(shù)和多態(tài)性
虛函數(shù)(virtualfunction)和多態(tài)性(polymorphism)使得設(shè)計(jì)和實(shí)現(xiàn)易于擴(kuò)展的系統(tǒng)成為可能。
在程序開(kāi)發(fā)中,不論類(lèi)是否已經(jīng)建立,程序員都可以利用虛函數(shù)和多態(tài)性先編寫(xiě)處理這些類(lèi)的對(duì)象的程序。如果有些類(lèi)要從基類(lèi)派生,那么程序可以提供操作基類(lèi)對(duì)象的通用框架,然后由派生類(lèi)對(duì)象對(duì)該框架作很好的加工。例如,一個(gè)多邊形可以是矩形(Rectangle)、正方形(Square)、三角形(Triangle)等,它們都可成為多邊形類(lèi)(Polygon)的派生類(lèi)。為了高效的繪制各自的形狀,每一個(gè)類(lèi)都需要有一個(gè)自己的draw函數(shù),這些函數(shù)的程序代碼是不相同的。當(dāng)需要繪制一個(gè)形狀時(shí),不管它是什么形狀,把它作為基類(lèi)polygon的對(duì)象來(lái)處理是再好不過(guò)了。然后,只需要簡(jiǎn)單的調(diào)用基類(lèi)polygon的函數(shù)draw,并讓程序動(dòng)態(tài)的確定使用哪一個(gè)派生類(lèi)的draw函數(shù)。
為了使這種方法可行,我們把基類(lèi)中的函數(shù)聲明為虛函數(shù)draw,然后在每個(gè)派生類(lèi)中重新定義函數(shù)draw,使之能夠繪制合適的形狀。虛函數(shù)的聲明方法是在基類(lèi)的函數(shù)原型前加上關(guān)鍵字virtual。
在類(lèi)的繼承層次中,如果某一個(gè)類(lèi)的定義里聲明了一個(gè)虛函數(shù),那么從該類(lèi)之后的繼承層次結(jié)構(gòu)中都是虛函數(shù)。
沒(méi)有定義虛函數(shù)的派生類(lèi)就簡(jiǎn)單地繼承其直接基類(lèi)的虛函數(shù);如果在派生類(lèi)中重新定義虛函數(shù),那么重新定義的虛函數(shù)應(yīng)當(dāng)與其基類(lèi)的虛函數(shù)有相同的返回類(lèi)型,參數(shù)個(gè)數(shù)和參數(shù)類(lèi)型。如果在基類(lèi)的虛函數(shù)原型中加上記號(hào)“=0”,該虛函數(shù)就成為純虛函數(shù)。
純虛函數(shù)的實(shí)現(xiàn)代碼應(yīng)當(dāng)由派生類(lèi)提供,記號(hào)“=0”使得基類(lèi)成為一個(gè)抽象類(lèi),抽象類(lèi)不能用來(lái)建立實(shí)例化的對(duì)象。其唯一用途是為其他類(lèi)提供合適的基類(lèi),其他類(lèi)可從它這里繼承接口。例如,基類(lèi)polygon有一個(gè)純虛函數(shù)virtualvoiddraw()=0,因此polygon就成為抽象類(lèi),它沒(méi)有實(shí)例化對(duì)象,也不用來(lái)建立實(shí)例化對(duì)象,所有操作都沒(méi)有實(shí)現(xiàn)代碼?;?lèi)polygon作為抽象類(lèi),將使得draw成為所有的派生類(lèi)的接口。
C++支持多態(tài)性,所謂多態(tài)性是指“一個(gè)接口,多個(gè)算法”,即允許把一個(gè)接口用于一類(lèi)行為。不同的通過(guò)繼承而相關(guān)的類(lèi),它們的對(duì)象能夠?qū)ν粋€(gè)函數(shù)調(diào)用作出不同的響應(yīng)。
例如,有一個(gè)程序定義了三種不同數(shù)據(jù)類(lèi)型的順序表:一個(gè)用于整數(shù)型的值,一個(gè)用于浮點(diǎn)型的值,一個(gè)用于長(zhǎng)整數(shù)型的值。根據(jù)多態(tài)性,我們可以為Insert()和Remove()各創(chuàng)建三個(gè)函數(shù),編譯程序根據(jù)調(diào)用Insert()和Remove()時(shí)所帶參數(shù)的數(shù)據(jù)類(lèi)型,選擇適當(dāng)?shù)膶?shí)現(xiàn)函數(shù)。
多態(tài)性是通過(guò)虛函數(shù)實(shí)現(xiàn)的,當(dāng)通過(guò)基類(lèi)指針引用一個(gè)虛函數(shù)時(shí),C++會(huì)在與對(duì)象相關(guān)聯(lián)的派生類(lèi)中正確的選擇和使用重定義的函數(shù)。
使用虛函數(shù)和多態(tài)性能夠使成員函數(shù)的調(diào)用根據(jù)接收到該調(diào)用的對(duì)象的類(lèi)型產(chǎn)生不同的動(dòng)作。
多態(tài)性給了程序員極大的靈活性。多態(tài)性提高了軟件系統(tǒng)的可擴(kuò)展性。
盡管不能實(shí)例化抽象類(lèi)的對(duì)象,但可以聲明抽象(基)類(lèi)的指針。當(dāng)實(shí)例化了具體類(lèi)的對(duì)象后,可以用這種指針使派生類(lèi)對(duì)象具有多態(tài)操作的能力。
例2-8
用虛函數(shù)和多態(tài)性計(jì)算工資//EMPLOY2.H//抽象基類(lèi)Employee#ifndefEMPLOY2_H#defineEMPLOY2_HclassEmployee{public: Employee(const
char*,const
char*);~Employee();
constchar*getFirstName()const;
constchar*getLastName()const;//純虛函數(shù)使類(lèi)Employee成為抽象基類(lèi)virtualfloatearnings()const=0;//純虛函數(shù)virtualvoidprint()const=0;//純虛函數(shù)
private:char*firstName;
char*lastName;};#endif
//EMPLOY2.CPP//定義抽象基類(lèi)Employee成員函數(shù)//注:虛函數(shù)沒(méi)有定義#include<iostream.h>#include<string.h>#include<assert.h>#include"employ2.h"/*構(gòu)造函數(shù)動(dòng)態(tài)地為名和姓分配內(nèi)存,并用函數(shù)strcpy把名和姓拷貝到對(duì)象中*/Employee::Employee(constchar*first,constchar*last){firstName=new
char[strlen(first)+1];
assert(firstName!=0);//測(cè)試內(nèi)存分配是否成功strcpy(firstName,first);lastName=newchar[strlen(last)+1]; assert(lastName!=0);//測(cè)試內(nèi)存分配是否成功strcpy(lastName,last);}
//析構(gòu)函數(shù)釋放動(dòng)態(tài)分配的內(nèi)存Employee::~Employee(){delete[]firstName;delete[]lastName;}//返回指向雇員名的指針constchar*Employee::getFirstName()const{ /*const限定符防止調(diào)用者修改私有數(shù)據(jù)。為防止引用沒(méi)有定義的指針,
調(diào)用者應(yīng)該在析構(gòu)釋放內(nèi)存之前拷貝返回的字符串*/
returnfirstName;//調(diào)用者必須釋放內(nèi)存}
//返回指向雇員姓的指針constchar*Employee::getLastName()const{/*const限定符防止調(diào)用者修改私有數(shù)據(jù)。為防止引用沒(méi)有定義的指針,調(diào)用者應(yīng)該在析構(gòu)釋放內(nèi)存之前拷貝返回的字符串*/
returnlastName;//調(diào)用者必須釋放內(nèi)存}//BOSS1.H//從類(lèi)Employee派生出來(lái)的類(lèi)Boss#ifndefBOSS1_H#defineBOSS1_H#include"employ2.h"
classBoss:publicEmployee{public:Boss(constchar*,constchar*,float=0.0);voidsetWeeklySalary(float);virtualfloatearnings()const;virtualvoidprint()const;private: floatweeklySalary;};#endif//BOSS1.CPP//定義類(lèi)Boss的成員函數(shù)#include<iostream.h>#include"boss1.h“
//類(lèi)Boss的構(gòu)造函數(shù)Boss::Boss(constchar*first,constchar*last,floats) :Employee(first,last)//調(diào)用基類(lèi)的構(gòu)造函數(shù){weeklySalary=s>0?s:0;}//設(shè)置老板的工資voidBoss::setWeeklySalary(floats){weeklySalary=s>0?s:0;}//返回老板工資floatBoss::earnings()const{returnweeklySalary;}//打印老板的姓名voidBoss::print()const{cout<<"\nBoss:"<<getFirstName()<<''<<getLastName();}MIS1.H//從類(lèi)Employee派生出來(lái)的類(lèi)CommissionWorker#ifndefCOMMIS1_H#defineCOMMIS1_H#include"employ2.h“classCommissionWorker:publicEmployee{public:CommissionWorker(constchar*,constchar*,float=0.0,float=0.0,int=0);voidsetSalary(float);voidmission(float);voidSetQuantity(int);virtualfloatearnings()const;virtualvoidprint()const;private:floatsalary;//每周的基本工資 floatcommission;//每件產(chǎn)品的回扣量 intquantity;//一周的銷(xiāo)售量};#endifMIS1.CPP//定義類(lèi)CommissionWorker的成員函數(shù)#include<iostream.h>#include"commis1.h"http://類(lèi)CommissionWorker的構(gòu)造函數(shù)missionWorker(constchar*first, constchar*last,floats,floatc,intq):Employee(first,last)//調(diào)用基類(lèi)的構(gòu)造函數(shù){salary=s>0?s:0;commission=c>0?c:0;quantity=q>0?q:0;}//設(shè)置銷(xiāo)售員每周的基本工資voidCommissionWorker::setSalary(floats){salary=s>0?s:0;}//設(shè)置銷(xiāo)售員的回扣額voidmission(floatc){ commission=c>0?c:0; }//設(shè)置銷(xiāo)售員的銷(xiāo)售量voidCommissionWorker::SetQuantity(intq){quantity=q>0?q:0;}//計(jì)算銷(xiāo)售員的收入floatCommissionWorker::earnings()const{returnmission*quantity;}//打印銷(xiāo)售員的姓名voidCommissionWorker::print()const{ cout<<"\nCommissionWorker:"<<getFirstName()<<''<<getLastName();}//PIECE1.H//從類(lèi)Employee派生出來(lái)的類(lèi)PieceWorker
#ifndefPIECE1_H#definePIECE1_H#include"employ2.h“classPieceWorker:publicEmployee{public: PieceWorker(constchar*,constchar*,float=0.0,int=0);voidsetWage(float);
voidSetQuantity(int);
virtualfloatearnings()const; virtualvoidprint()const;private:
floatwagePetPiece;//每件產(chǎn)品的報(bào)酬
intquantity;//一周生產(chǎn)的產(chǎn)品數(shù)量};#endif
//PIECE1.CPP//定義類(lèi)PieceWorker的成員函數(shù)#include<iostream.h>#include"piece1.h“}//類(lèi)PieceWorker的構(gòu)造函數(shù)PieceWorker::PieceWorker(constchar*first,constchar*last,floatw,intq) :Employee(first,last)//調(diào)用基類(lèi)的構(gòu)造函數(shù){wagePetPiece=w>0?w:0; quantity=q>0?q:0;//設(shè)置每件產(chǎn)品的報(bào)酬voidPieceWorker::setWage(floatw){wagePerPiece=w>0?w:0;}//設(shè)置生產(chǎn)的產(chǎn)品數(shù)量voidPieceWorker::SetQuantity(intq){quantity=q>0?q:0; }//計(jì)算計(jì)件工的收入floatPieceWorker::earnings()const
{returnquantity*wagePetPiece;}
//打印計(jì)件工的姓名voidPieceWorker::print()const{
cout<<"\nPieceWorker:"<<getFirstName()<<''<<getLastName();}//HOURLY1.H//從類(lèi)Employee派生出來(lái)的類(lèi)HourlyWorker
#ifndefHOURLY1_H#defineHOURLY1_H#include"employ2.h"
classHourlyWorker:publicEmployee{public:HourlyWorker(constchar*,constchar*,float=0.0,float=0.0);
voidsetWage(float); voidsetHours(float);
virtualfloatearnings()const;virtualvoidprint()const;private:floatwage;//每小時(shí)報(bào)酬
floathours;//一周工作時(shí)數(shù)};#endif
//HOURLY1.CPP//定義類(lèi)HourlyWorker的成員函數(shù)#include<iostream.h>#include"hourly1.h“//類(lèi)HourlyWorker的構(gòu)造函數(shù)HourlyWorker::HourlyWorker(constchar*first,constchar*last,floatw,floath) :Employee(first,last)//調(diào)用基類(lèi)的構(gòu)造函數(shù){wage=w>0?w:0; hours=h>=0&&h<168?h:0;}//設(shè)置每小時(shí)報(bào)酬voidHourlyWorker::setWage(floatw){ wage=w>0?w:0; }//設(shè)置工作時(shí)數(shù)voidHourlyWorker::setHours(floath){ hours=h>=0&&h<168?h:0;}//返回小時(shí)工的收入floatHourlyWorker::earnings()const
{returnwage*hours;}//打印小時(shí)工的姓名voidHourlyWorker::print()const{cout<<"\nHourlyWorker:"<<getFirstName()<<''<<getLastName();}2.9.2動(dòng)態(tài)聯(lián)編動(dòng)態(tài)聯(lián)編是指在系統(tǒng)運(yùn)行時(shí)確定對(duì)象的類(lèi)型,動(dòng)態(tài)聯(lián)編提供了很大的便利性,有時(shí)也稱(chēng)為后期聯(lián)編。
在面向?qū)ο蠓椒ㄖ?動(dòng)態(tài)聯(lián)編是和多態(tài)性及繼承性緊密相關(guān)的。因?yàn)?過(guò)程具有多態(tài)引用機(jī)制主要是依賴(lài)于引用的動(dòng)態(tài)類(lèi)型。例2-9給出了使用上一節(jié)所定義的類(lèi)的測(cè)試程序。我們將以此例來(lái)討論靜態(tài)聯(lián)編和動(dòng)態(tài)聯(lián)編。程序首先將ptr聲明為基類(lèi)指針類(lèi)型Employee*。Main()函數(shù)中的四小段代碼是類(lèi)似的,因此我們只討論處理Boss對(duì)象的第一段代碼。例2-9
根據(jù)員工類(lèi)型計(jì)算工資的程序
//Example2-9.cpp//類(lèi)Employee層次結(jié)構(gòu)的測(cè)試程序
#include<iostream.h>#include<iomanip.h>#include"empoly2.h"#include"boss.h"#include"commis1.h"#include"piece1.h"#include"hourly1.h“main(){//設(shè)置輸出格式cout<<setiosflags(ios::showpoint)<<setprecision(2);Employee*ptr;//基類(lèi)指針Bossb("John","Smith",800.00);ptr=&b;//指向派生類(lèi)對(duì)象的基類(lèi)指針ptr->print();//動(dòng)態(tài)聯(lián)編cout<<"earned$"<<ptr->earnings();//動(dòng)態(tài)聯(lián)編b.print();//靜態(tài)聯(lián)編cout<<“earned$”<<b.earnings();//靜態(tài)聯(lián)編CommissionWorkerc("Sue","Jones",200.0,3.0,150);ptr=&c;//指向派生類(lèi)對(duì)象的基類(lèi)指針ptr->print();//動(dòng)態(tài)聯(lián)編cout<<"earned$"<<ptr->earnings();//動(dòng)態(tài)聯(lián)編c.print();//靜態(tài)聯(lián)編cout<<"earned$"<<c.earnings();//靜態(tài)聯(lián)編PieceWorkerp("Bob","Lewis",2.5,2
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 《AQ 1035-2007煤礦用單繩纏繞式礦井提升機(jī)安全檢驗(yàn)規(guī)范》專(zhuān)題研究報(bào)告
- 2026年重慶五一職業(yè)技術(shù)學(xué)院?jiǎn)握新殬I(yè)傾向性測(cè)試題庫(kù)及答案詳解一套
- 民間借款不動(dòng)產(chǎn)抵押擔(dān)保協(xié)議
- 中央空調(diào)清洗技師(中級(jí))考試試卷及答案
- 2026年衛(wèi)生院護(hù)理的工作計(jì)劃(3篇)
- 2026年護(hù)理部工作計(jì)劃(5篇)
- 2026年醫(yī)院檢驗(yàn)科工作計(jì)劃與建議
- 2025年體育專(zhuān)用地坪漆項(xiàng)目建議書(shū)
- 2025年帶電作業(yè)技術(shù)會(huì)議:面向110-220kV變電站引線(xiàn)帶電斷接機(jī)器人技術(shù)的探索與研究
- 遼寧省2025秋九年級(jí)英語(yǔ)全冊(cè)Unit2Ithinkthatmooncakesaredelicious寫(xiě)作能力提升練課件新版人教新目標(biāo)版
- 2025-2026學(xué)年教科版小學(xué)科學(xué)新教材三年級(jí)上冊(cè)期末復(fù)習(xí)卷及答案
- 中投公司高級(jí)職位招聘面試技巧與求職策略
- 2026中國(guó)大唐集團(tuán)資本控股有限公司高校畢業(yè)生招聘考試歷年真題匯編附答案解析
- 2025福建三明市農(nóng)業(yè)科學(xué)研究院招聘專(zhuān)業(yè)技術(shù)人員3人筆試考試備考題庫(kù)及答案解析
- 統(tǒng)編版(部編版)小學(xué)語(yǔ)文四年級(jí)上冊(cè)期末測(cè)試卷( 含答案)
- 養(yǎng)老金贈(zèng)予合同范本
- 2025年南網(wǎng)能源公司社會(huì)招聘(62人)考試筆試參考題庫(kù)附答案解析
- 2025年河南中原國(guó)際會(huì)展中心有限公司社會(huì)招聘44名筆試備考題庫(kù)附答案解析
- 推廣示范基地協(xié)議書(shū)
- 消防員心理健康教育課件
- 2025年服裝行業(yè)五年發(fā)展時(shí)尚產(chǎn)業(yè)與可持續(xù)發(fā)展報(bào)告
評(píng)論
0/150
提交評(píng)論