版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第2章類和對象本章主要內(nèi)容:棧和隊(duì)列簡單應(yīng)用
抽象、封裝和信息隱蔽
類聲明和類實(shí)現(xiàn)
對象數(shù)組和動(dòng)態(tài)對象
常用容器使用舉例
類的嵌套定義
類類型的數(shù)據(jù)成員和has-a關(guān)系
典型范例——簡單集合類
特殊機(jī)制
計(jì)算機(jī)學(xué)院李衛(wèi)明2.1棧和隊(duì)列簡單應(yīng)用問題:編寫要求程序輸入若干個(gè)整數(shù),將輸入后的正整數(shù)和負(fù)整數(shù)分別保存起來,輸入完成后,首先將以輸入相反的次序輸出所有保存的正整數(shù),再以輸入相同次序輸出所有保存的負(fù)整數(shù),正整數(shù)和負(fù)整數(shù)輸出各占一行。輸入樣例: 28-10-2030-94-2輸出樣例: 43082-10-20-9-2
問題看似簡單,要比較完美解答還是需要解決很多問題:如何判斷輸入結(jié)束、存放輸入數(shù)據(jù)的內(nèi)存空間需要多少、如何管理這些內(nèi)存空間、如何使程序的可讀性好?計(jì)算機(jī)學(xué)院李衛(wèi)明
我們先來分析如何判斷輸入結(jié)束問題。表達(dá)式cin>>x執(zhí)行一次,表達(dá)式執(zhí)行結(jié)果可以用來判別是否讀入了一個(gè)整數(shù),結(jié)果不成立,代表輸入已結(jié)束;結(jié)果成立,代表已讀入一個(gè)正整數(shù),保存在整形變量x中。while(cin>>x){...}循環(huán)語句可以完成若干個(gè)整數(shù)的輸入。用鍵盤輸入時(shí),windows系統(tǒng)下,可以在輸入尾部,新行開始時(shí),在按下ctrl鍵同時(shí)按下z鍵,然后再輸入回車模擬輸入結(jié)束,unix系統(tǒng)下,可以在輸入尾部,新行開始時(shí),在按下ctrl鍵同時(shí)按下d鍵,然后再輸入回車模擬輸入結(jié)束。計(jì)算機(jī)學(xué)院李衛(wèi)明再來考慮數(shù)據(jù)保存問題。這個(gè)問題中,正整數(shù)的保存和輸出符合最后保存最先輸出的特點(diǎn),負(fù)整數(shù)的保存和輸出符合先保存先輸出特點(diǎn),這是程序設(shè)計(jì)中常見的兩種需求。我們先引入程序設(shè)計(jì)中經(jīng)常使用的兩個(gè)重要結(jié)構(gòu):棧和隊(duì)列。具有最后保存最先輸出(LIFO:LastIn,FirstOut)特性的數(shù)據(jù)結(jié)構(gòu)稱為棧(stack),具有最先保存最先輸出(FIFO:FirstInFirstOut)特性的數(shù)據(jù)結(jié)構(gòu)稱為隊(duì)列(queue)。計(jì)算機(jī)學(xué)院李衛(wèi)明
棧和隊(duì)列圖2.1是棧結(jié)構(gòu)示意圖,棧主要支持入棧、出棧、取棧頂元素、判空等操作。圖2.2是隊(duì)列結(jié)構(gòu)示意圖,隊(duì)列主要支持入隊(duì)列、出隊(duì)列、取隊(duì)首元素等操作。我們用一個(gè)棧保存正整數(shù),用一個(gè)隊(duì)列保存負(fù)整數(shù),在輸入完成后,再將棧內(nèi)正整數(shù)全部取出并輸出,將隊(duì)列內(nèi)保存的負(fù)整數(shù)全部取出并輸出,上述問題就可以解決。圖2.1
棧示意圖圖2.2
隊(duì)列示意圖C++STL(StandardTemplateLibrary)標(biāo)準(zhǔn)模板庫提供了棧類模板和隊(duì)列類模板,類模板可以產(chǎn)生類,關(guān)于類模板概念,在本書第6章討論。在C++中,類具有C語言中普通類型相似的作用,與C語言定義普通類型變量相同,C++可以用下述語句建立一個(gè)整數(shù)棧S:stack<int>S;stack<in>可以看作一個(gè)整數(shù)棧類,S是具有整數(shù)棧類類型的實(shí)例,也可稱為一個(gè)棧對象。棧對象S建立時(shí)具有無元素的空棧狀態(tài),S.push(x);語句可以將x壓入棧S,入棧操作內(nèi)部可以保證元素壓棧所需的空間,S.top()返回非空棧S的棧頂元素的引用,S.pop()彈出非空棧S的棧頂元素,S.empty()用來判別S是否為空棧。使用STL棧類模板需要包含標(biāo)準(zhǔn)頭文件stack。3,2,12,3,1C++用下述語句建立一個(gè)整數(shù)隊(duì)列Q:queue<int>Q;queue<int>可以看作一個(gè)整數(shù)隊(duì)列類,Q是具有整數(shù)隊(duì)列類類型的實(shí)例,也可稱為一個(gè)隊(duì)列對象。隊(duì)列對象Q建立時(shí)具有無元素的空隊(duì)列狀態(tài),Q.push(x);語句可以將x入隊(duì)列Q,入隊(duì)列操作內(nèi)部可以保證元素入隊(duì)列需要的空間,Q.front()返回非空隊(duì)列Q的隊(duì)首元素的引用,Q.pop()彈出非空隊(duì)列Q的隊(duì)首元素,Q.empty()用來判別Q是否為空隊(duì)列。使用STL隊(duì)列類模板需要包含標(biāo)準(zhǔn)頭文件queue。3,2,12,3,1問題解決方案//Ex2.11#include<iostream>2#include<stack>3#include<queue>4usingnamespacestd;5intmain()6{7stack<int>S;//建立空整數(shù)棧
8queue<int>Q;//建立空整數(shù)隊(duì)列
910intx;11while(cin>>x)//循環(huán)輸入成功
12{13if(x>0)14S.push(x);//入棧
15else16Q.push(x);//入隊(duì)列
17}1819while(!S.empty())//循環(huán)判棧非空
20{21x=S.top();//取棧頂元素
22S.pop();//出棧
23cout<<x<<"\t";24}25cout<<endl;26while(!Q.empty())//循環(huán)判隊(duì)列非空
27{28x=Q.front();//取隊(duì)首元素
29Q.pop();//出隊(duì)列
30cout<<x<<"\t";31}32cout<<endl;33}計(jì)算機(jī)學(xué)院李衛(wèi)明上述樣例里,S是一個(gè)具有后進(jìn)先出特性的整數(shù)棧,Q是具有先進(jìn)先出特性的整數(shù)隊(duì)列,分別是2個(gè)不同類型的對象,具有不同的行為能力(功能)和內(nèi)部狀態(tài)?,F(xiàn)實(shí)世界中客觀事物和思維世界中的抽象概念都可以稱為對象,每個(gè)對象都具有行為能力和內(nèi)部狀態(tài)等屬性,一個(gè)類是具有相同行為能力對象的抽象,是用于創(chuàng)建對象的藍(lán)圖或軟件模板,如樣例里的stack<int>類和queue<int>類。類和對象是面向?qū)ο蟪绦蛟O(shè)計(jì)技術(shù)中的最基本的概念,對象是類的具體實(shí)例,是具有類類型的變量,不同類的對象具有不同的行為能力和內(nèi)部狀態(tài),同一個(gè)類的多個(gè)對象具有相同的行為能力,每個(gè)對象具有獨(dú)立的狀態(tài),在不同時(shí)間狀態(tài)也不同。本章開始,我們學(xué)習(xí)如何設(shè)計(jì)類和實(shí)現(xiàn)類,再利用類定義對象,解決問題,進(jìn)行面向?qū)ο蟪绦蛟O(shè)計(jì)。3,2,12,3,1STL棧類封裝主要成員介紹stack<T>S1;聲明一個(gè)空棧S1;stack<T>S2(S1);聲明一個(gè)初始內(nèi)容復(fù)制自S1的棧S2;成員函數(shù):語法:boolempty()const;如當(dāng)前堆棧為空,empty()函數(shù)返回true否則返回false.語法:voidpush(constT&x);push()函數(shù)將元素x入棧。語法:voidpop();pop()函數(shù)移除堆棧中最頂層元素。語法:size_typesize()const;size()函數(shù)返當(dāng)前堆棧中的元素?cái)?shù)目。語法:T&top()const;top()函數(shù)返回對棧頂元素的引用.3,2,12,3,1
STL隊(duì)列類封裝主要成員介紹queue<T>Q1;聲明一個(gè)空隊(duì)列Q1;queue<T>Q2(Q1);聲明一個(gè)隊(duì)列Q2復(fù)制自Q1;語法:voidpush(constT&x);push()函數(shù)將元素x入隊(duì)列。語法:voidpop();pop彈出隊(duì)列中的第一個(gè)元素,返回的是一個(gè)void;語法:T&front()const;front()函數(shù)返回對隊(duì)首元素的引用.語法:boolempty()const;如當(dāng)前隊(duì)列為空,empty()函數(shù)返回true否則返回false.語法:size_typesize()const;size()函數(shù)返當(dāng)前隊(duì)列中的元素?cái)?shù)目。3,2,12,3,1
2.2 抽象、封裝和信息隱蔽
2.2.1抽象現(xiàn)實(shí)世界中客觀事物和抽象概念都可以稱為對象面向?qū)ο蠓椒ㄖ械某橄笫侵笇唧w問題即對象進(jìn)行概括,抽出一類對象的共性并加以描述的過程。面向?qū)ο蟮能浖_發(fā)中,首先應(yīng)該對要解決的問題抽象成類,然后才是解決問題的過程。抽象有兩個(gè)方面:數(shù)據(jù)抽象和行為抽象。數(shù)據(jù)抽象是描述某類對象的屬性或狀態(tài),行為抽象是描述某類對象的共同行為或共同功能。計(jì)算機(jī)學(xué)院李衛(wèi)明先拿時(shí)鐘為例進(jìn)行抽象。假設(shè)我們需要關(guān)心的時(shí)鐘時(shí)間精度到秒,每個(gè)時(shí)鐘都有具體時(shí)間,我們用時(shí)、分、秒表示,用三個(gè)整型變量來存儲,舍棄指針長短、時(shí)鐘外觀、重量等非本質(zhì)的屬性,這就是時(shí)鐘的數(shù)據(jù)抽象。所有時(shí)鐘都有顯示時(shí)間和設(shè)置時(shí)間等功能,舍棄鬧鈴等不關(guān)心的功能,這就是時(shí)鐘的行為抽象。形成如下時(shí)鐘抽象:時(shí)鐘(Clock)數(shù)據(jù)抽象:時(shí)(intm_iHour)、分(intm_iMinute)、秒(intm_iSecond);行為抽象:顯示時(shí)間ShowTime();設(shè)置時(shí)間SetTime(intiHour,intiMinute,intiSecond);計(jì)算機(jī)學(xué)院李衛(wèi)明再如上節(jié)出現(xiàn)的整數(shù)棧??紤]一根一端封閉、另一端打開的鋼管,從打開的那端可以放入或取出標(biāo)有整數(shù)的玻璃球,鋼管可以放入、取出玻璃球,可以判斷出鋼管里是否還有玻璃球。對具有這類特征的物體進(jìn)行抽象,可將鋼管看成一個(gè)棧,封閉的這端稱為棧底,鋼管打開的那端最上面物體的所在位置稱為棧頂,沒有物體時(shí),棧底就是棧頂。鋼管里存放的若干內(nèi)標(biāo)數(shù)字的玻璃球就代表鋼管的狀態(tài),形成數(shù)據(jù)抽象:某個(gè)時(shí)刻棧中從棧頂?shù)綏5醉樞蚺帕械恼麛?shù)序列,隨著棧的操作而變化;建空鋼管、放玻璃球、彈出玻璃球、棧頂玻璃球、看鋼管內(nèi)是否有玻璃球這些操作形成棧的行為抽象:棧初始化、入棧、出棧、取棧頂、判棧空。計(jì)算機(jī)學(xué)院李衛(wèi)明合在一起,形成整數(shù)棧的抽象:棧(satck)數(shù)據(jù)抽象:
從棧頂?shù)綏5醉樞蚺帕械恼麛?shù)序列;行為抽象:
初始化成空棧;
元素入棧;
非空時(shí)元素出棧;
非空時(shí)取棧頂元素;
判???計(jì)算機(jī)學(xué)院李衛(wèi)明程序設(shè)計(jì)中經(jīng)常遇到集合概念,可以形成如下整數(shù)集合的抽象:整數(shù)集合數(shù)據(jù)抽象:
若干個(gè)互不相同的整數(shù);行為抽象:
初始化成空集;
顯示集合;
增加一個(gè)元素;
刪除一個(gè)元素;
判斷是否包含指定元素;2個(gè)集合并運(yùn)算,返回包含2個(gè)集合所有元素的新集合;2個(gè)集合交運(yùn)算,返回包含2個(gè)集合所有公共元素的新集合;2個(gè)集合差運(yùn)算,返回所有在第1個(gè)集合但不在第2個(gè)集合元素的新集合;計(jì)算機(jī)學(xué)院李衛(wèi)明上述三個(gè)抽象的例子具有一定的代表性,第1個(gè)時(shí)鐘的狀態(tài)比較簡單,用固定數(shù)量的內(nèi)置數(shù)據(jù)類型就可表示,棧和集合的狀態(tài)比較復(fù)雜,元素需要連續(xù)存放在數(shù)組、動(dòng)態(tài)分配的類似數(shù)組空間里或鏈表里,第3個(gè)集合的并、交、差操作還涉及3個(gè)集合實(shí)體,也就是三個(gè)集合對象計(jì)算機(jī)學(xué)院李衛(wèi)明2.2.2
封裝和信息隱蔽封裝就是將抽象得到的數(shù)據(jù)抽象和行為(或功能)抽象相結(jié)合,形成一個(gè)有機(jī)的整體,在面向?qū)ο蟪绦蛟O(shè)計(jì)中,也就是將數(shù)據(jù)與操作數(shù)據(jù)的函數(shù)代碼進(jìn)行有機(jī)的結(jié)合,形成“類”,其中的數(shù)據(jù)和函數(shù)都是類的成員,分別稱為數(shù)據(jù)成員和函數(shù)成員。類的成員具有私有或公有訪問控制,類的用戶從類外只可訪問類的公有成員,不可訪問類的私有成員,實(shí)現(xiàn)了信息隱蔽,類的所有公有成員形成了類的對外接口協(xié)議。就像用戶只需了解集成電路的管腳定義,無需了解集成電路的設(shè)計(jì)和實(shí)現(xiàn)細(xì)節(jié),用戶只需關(guān)心汽車輪胎的對外參數(shù),無需了解輪胎的生產(chǎn)過程一樣,類的用戶只需要了解類對外公開的成員,不需要了解類內(nèi)部隱蔽的私有成員和類成員函數(shù)實(shí)現(xiàn)細(xì)節(jié),即使將程序中的一個(gè)類替換為另一個(gè)具有相同對外接口協(xié)議的類,程序功能也不會(huì)有影響,使程序各部分的分工合理、職責(zé)清楚,程序具有良好的可讀性好和可維護(hù)性,有利于大型程序開發(fā)?,F(xiàn)代程序設(shè)計(jì)中,一般將數(shù)據(jù)成員封裝成私有的,有利于類的實(shí)現(xiàn)和使用。計(jì)算機(jī)學(xué)院李衛(wèi)明2.3 類聲明和類實(shí)現(xiàn)C++使用關(guān)鍵字class用來表示類類型,用public表示公有成員,用private表示私有成員,上節(jié)抽象形成的時(shí)鐘類聲明如下:classCClock{public:voidShowTime()const;voidSetTime(intiHour,intiMinute,intiSecond);private:intm_iHour,m_iMinute,m_iSecond;};這個(gè)類聲明定義了組成類的數(shù)據(jù)成員和函數(shù)成員,包括它們的訪問控制屬性,是一個(gè)定義性聲明。計(jì)算機(jī)學(xué)院李衛(wèi)明圖2.3是CClockUML類圖,具有簡單直觀的優(yōu)點(diǎn)。統(tǒng)一建模語言UML(UnifiedModelingLanguage)是面向?qū)ο蠓治鲋幸环N重要的建模工具,UML是一種用于說明、可視化、構(gòu)建和編寫一個(gè)正在開發(fā)的、面向?qū)ο蟮?、軟件密集系統(tǒng)的制品的開放方法。UML展現(xiàn)了一系列最佳工程實(shí)踐,這些最佳實(shí)踐在對大規(guī)模、復(fù)雜系統(tǒng)進(jìn)行建模方面,特別是在軟件架構(gòu)層次建模方面,已經(jīng)被驗(yàn)證有效。UML有多種圖形表示方法,本書用UML來表示類圖、類之間的聚合、泛化關(guān)系。UML類圖有類名、數(shù)據(jù)成員、函數(shù)成員三部分組成,+表示公有成員,-表示私有成員。類成員的作用域是本類。計(jì)算機(jī)學(xué)院李衛(wèi)明圖2.3
CClock類圖上述時(shí)鐘類的定義里,m_iHour、m_iMinute、m_iSecond是時(shí)鐘類的三個(gè)數(shù)據(jù)成員,用來表示時(shí)鐘的狀態(tài),三個(gè)數(shù)據(jù)成員都是私有的,具有整形類型。本講義中,數(shù)據(jù)成員命名大都以m_或_開頭,以區(qū)分類成員和其它局部對象、形參。數(shù)據(jù)成員作用域是該類。一個(gè)類可以有多個(gè)數(shù)據(jù)成員,數(shù)據(jù)成員類型可以是內(nèi)置數(shù)據(jù)類型、內(nèi)置數(shù)據(jù)類型的復(fù)合型,還可以是其它的類類型,形成類之間的聚合關(guān)系,類之間的聚合關(guān)系將在本章第7節(jié)討論。類類型的變量一般稱為對象。數(shù)據(jù)成員用于表示對象的狀態(tài),在對象的生存期內(nèi),類的所有成員函數(shù)都必須維護(hù)對象的數(shù)據(jù)成員。成員函數(shù)臨時(shí)使用的變量不應(yīng)該作為類的數(shù)據(jù)成員。計(jì)算機(jī)學(xué)院李衛(wèi)明2.3.1數(shù)據(jù)成員類的成員函數(shù)用于表示類對象的行為能力或功能,上述時(shí)鐘類有ShowTime和SetTime兩個(gè)成員函數(shù)。成員函數(shù)的作用域是該類,聲明類似于C/C++的普通函數(shù),不同的是,成員函數(shù)一般通過對象訪問,調(diào)用成員函數(shù)的當(dāng)前對象實(shí)際是成員函數(shù)隱含的參數(shù),成員函數(shù)除了可以訪問形參外,還可以訪問表示當(dāng)前對象狀態(tài)的數(shù)據(jù)成員。計(jì)算機(jī)學(xué)院李衛(wèi)明2.3.2函數(shù)成員類的成員函數(shù)的定義可以直接定義在類聲明內(nèi)部,含SetTime成員函數(shù)定義的時(shí)鐘類定義頭文件改寫如下:#ifndefCLOCK_H_INCLUDED#defineCLOCK_H_INCLUDEDclassCClock{public:voidShowTime()const;voidSetTime(intiHour,intiMinute,intiSecond){m_iHour=iHour;m_iMinute=iMinute;m_iSecond=iSecond;}private:intm_iHour,m_iMinute,m_iSecond;};#endif//CLOCK_H_INCLUDED計(jì)算機(jī)學(xué)院李衛(wèi)明類的成員函數(shù)的實(shí)現(xiàn)也可以定義在類定義外。不同的類可以具有同名的成員函數(shù),類名::用于界定成員函數(shù)屬于哪個(gè)類。類成員函數(shù)的實(shí)現(xiàn)代碼一般位于.cpp源程序文件內(nèi)。在類體外定義成員函數(shù)的一般形式為:返回值類型類名::成員函數(shù)名(形參表){
成員函數(shù)的函數(shù)體}
其中“::”是作用域運(yùn)算符。計(jì)算機(jī)學(xué)院李衛(wèi)明如:#include<iostream>usingnamespacestd;#include"clock.h"voidCClock::ShowTime()const{cout<<m_iHour<<":"<<m_iMinute<<":"<<m_iSecond<<endl;}ShowTime成員函數(shù)后面的const用于聲明成員函數(shù)不會(huì)改變當(dāng)前對象的狀態(tài),也就是不會(huì)修改當(dāng)前對象的數(shù)據(jù)成員,這樣的成員函數(shù)也稱為常成員函數(shù)。計(jì)算機(jī)學(xué)院李衛(wèi)明與普通函數(shù)一樣,成員函數(shù)也支持內(nèi)聯(lián)方式。實(shí)現(xiàn)在類定義內(nèi)部的成員函數(shù)默認(rèn)為內(nèi)聯(lián)函數(shù),實(shí)現(xiàn)在類外部的成員函數(shù),可以在成員函數(shù)聲明前加inline關(guān)鍵字實(shí)現(xiàn)內(nèi)聯(lián)函數(shù)。內(nèi)聯(lián)函數(shù)的定義一般位于頭文件內(nèi)。同樣,成員函數(shù)也支持函數(shù)重載,重載規(guī)則也與普通函數(shù)重載規(guī)則一樣,即重載的成員函數(shù)參數(shù)個(gè)數(shù)不同或參數(shù)類型不同。除了內(nèi)聯(lián)函數(shù)和函數(shù)重載,成員函數(shù)一樣可以使用參數(shù)缺省值。類定義并且實(shí)現(xiàn)了所需類的成員函數(shù)后,類就可以在程序中使用。計(jì)算機(jī)學(xué)院李衛(wèi)明類中定義的數(shù)據(jù)和函數(shù)稱為這個(gè)類的成員。類成員具有訪問權(quán)限,訪問權(quán)限通過在類成員前面的關(guān)鍵字來定義。關(guān)鍵字private、protected和public代表訪問權(quán)限分別是私有、保護(hù)和公有訪問權(quán)限,其后定義的成員分別稱為私有成員、保護(hù)成員和公有成員。訪問權(quán)限用于控制對象的某個(gè)成員在程序中的可訪問性,類的上述成員的訪問權(quán)限遵守如下的訪問規(guī)則:(1)公有成員:類成員函數(shù)以及該類外對象都能夠引用這些公有成員。(2)私有成員:私有成員只能被類成員函數(shù)所訪問,而不能被該類外的對象直接訪問。(3)保護(hù)成員:保護(hù)成員只能被該類及其派生類的成員函數(shù)所訪問,不能被該類外及派生類的對象所直接訪問。類(class)成員缺省訪問控制屬性為私有。結(jié)構(gòu)(struct)成員缺省訪問控制屬性為公有,建議C++程序員使用盡量class。計(jì)算機(jī)學(xué)院李衛(wèi)明2.3.3訪問控制C++并未規(guī)定類定義中函數(shù)成員和數(shù)據(jù)成員的聲明次序,也并未規(guī)定訪問控制屬性關(guān)鍵字的出現(xiàn)次序和次數(shù)。為了有利于的程序可讀性,建議先聲明公有成員,再聲明私有成員,先聲明函數(shù)成員,再聲明數(shù)據(jù)成員。類定義的一般形式建議如下:class類名{public:公有函數(shù)成員private:
私有函數(shù)成員
private:
私有數(shù)據(jù)成員};計(jì)算機(jī)學(xué)院李衛(wèi)明一個(gè)類是具有相同特性的對象的抽象,對象是類的實(shí)例。在完成類的定義和函數(shù)成員的定義后,就可以定義具有類類型的變量,也就是對象,并可通過對象調(diào)用類的成員函數(shù)。正如變量定義一樣,對象定義的一般形式如下:類名
對象名;類名
對象名=初始化表達(dá)式;類名
對象名(初始化表達(dá)式);類名
對象名{初始化表達(dá)式};//C++11新增初始化方式類名
對象名列表;訪問對象數(shù)據(jù)成員和函數(shù)成員的方式如下:對象.數(shù)據(jù)成員名對象.函數(shù)成員(實(shí)參表)上述訪問語句是一個(gè)表達(dá)式,可以出現(xiàn)在更復(fù)雜的表達(dá)式或表達(dá)式語句中。計(jì)算機(jī)學(xué)院李衛(wèi)明2.3.4對象的定義//Ex2.2#include"clock.h"intmain(){CClockt1,t2;t1.SetTime(10,20,30);t2.SetTime(11,10,25);t1.ShowTime();t2.ShowTime();}上述程序執(zhí)行后輸出:10:20:3011:10:25計(jì)算機(jī)學(xué)院李衛(wèi)明計(jì)算機(jī)學(xué)院李衛(wèi)明本例局部時(shí)鐘對象t1、t2內(nèi)存狀態(tài)如圖2.4所示,對象位于運(yùn)行棧,main函數(shù)執(zhí)行結(jié)束,對象t1、t2撤銷。假設(shè)每個(gè)整形占4個(gè)字節(jié),t1、t2分別占12個(gè)字節(jié)。圖2.4局部對象t1、t2內(nèi)存狀態(tài)示意圖main函數(shù)里不可訪問私有成員,如添加下述語句:t1.m_iHour=10;編譯器將報(bào)錯(cuò)。當(dāng)然,如果將類聲明里數(shù)據(jù)成員的訪問控制改為public,編譯可以通過,但這樣處理違背了隱藏對象狀態(tài)的信息隱蔽原則。C++可以定義指向類的指針變量,通過指針也可以間接訪問對象成員。通過對象指針訪問成員的方式如下:對象指針->數(shù)據(jù)成員名對象指針->函數(shù)成員(實(shí)參表)相當(dāng)于:(*對象指針).數(shù)據(jù)成員名(*對象指針).函數(shù)成員(實(shí)參表)上述訪問語句也同樣是一個(gè)表達(dá)式,可以出現(xiàn)在更復(fù)雜的表達(dá)式或表達(dá)式語句中。
計(jì)算機(jī)學(xué)院李衛(wèi)明如main函數(shù)內(nèi)可以添加下列語句,完成Ex2.2一樣調(diào)用效果:CClock*p;//指針變量
p=&t1;//指向t1對象p->SetTime(10,20,30);//調(diào)用p所指對象的成員函數(shù)p->ShowTime();p=&t2;p->SetTime(11,10,25);p->ShowTime();
注意,指針變量和所指對象是2個(gè)不同類型的對象,相互獨(dú)立,指針類型變量本身不是所指類類型的對象。計(jì)算機(jī)學(xué)院李衛(wèi)明本章第1節(jié)樣例里整數(shù)棧對象S建立時(shí)就是空棧狀態(tài),整數(shù)隊(duì)列對象Q建立時(shí)就是空隊(duì)列狀態(tài)。這些對象的初始化狀態(tài)是在什么時(shí)候又是如何完成的?如果我們在前面的時(shí)鐘對象t1、t2建立后直接調(diào)用ShowTime成員函數(shù),我們會(huì)發(fā)現(xiàn)顯示的時(shí)間有些不確定。如果我們希望自己設(shè)計(jì)實(shí)現(xiàn)的時(shí)鐘類,也能像STL提供的整數(shù)棧類和整數(shù)隊(duì)列類一樣,建立的時(shí)鐘對象能具有0:0:0初始狀態(tài),或指定的其它初始狀態(tài),應(yīng)該如何處理?計(jì)算機(jī)學(xué)院李衛(wèi)明2.3.5構(gòu)造函數(shù)每個(gè)類對象建立時(shí)會(huì)自動(dòng)調(diào)用類的構(gòu)造函數(shù)。構(gòu)造函數(shù)也是類的成員函數(shù),構(gòu)造函數(shù)名字與類名相同,無返回值,也無返回類型void聲明。構(gòu)造函數(shù)還可以重載,容許一個(gè)類的多個(gè)對象使用不同的構(gòu)造函數(shù)構(gòu)造。如我們可以為時(shí)鐘類提供下列2個(gè)重載的構(gòu)造函數(shù)。CClock::CClock(){SetTime(0,0,0);}CClock::CClock(intiHour,intiMinute,intiSecond){SetTime(iHour,iMinute,iSecond);}計(jì)算機(jī)學(xué)院李衛(wèi)明這樣,建立時(shí)鐘類對象時(shí),如果沒有提供實(shí)參,時(shí)鐘對象建立時(shí)會(huì)自動(dòng)調(diào)用無參構(gòu)造函數(shù),如果提供指定時(shí)間作為實(shí)參,時(shí)鐘對象建立時(shí)會(huì)自動(dòng)調(diào)用第2個(gè)構(gòu)造函數(shù)。如執(zhí)行下述語句,時(shí)鐘對象t1、t2顯示的時(shí)間分別是0:0:0和6:10:20。
CClockt1,t2(6,10,20);t1.ShowTime();t2.ShowTime();上述建立t1、t2對象的第一個(gè)語句,定義的t1無實(shí)參,t1后不能加括號,否則t1會(huì)被認(rèn)為是一個(gè)返回時(shí)鐘對象的函數(shù)聲明,與本意不符。計(jì)算機(jī)學(xué)院李衛(wèi)明如果類沒有提供任何構(gòu)造函數(shù),編譯器會(huì)自動(dòng)合成一個(gè)無參構(gòu)造函數(shù),如下所示:CClock::CClock(){}它會(huì)逐個(gè)完成類數(shù)據(jù)成員構(gòu)造,對于類型為內(nèi)置數(shù)據(jù)類型、指針型的數(shù)據(jù)成員,構(gòu)造時(shí)未進(jìn)行初始化,也就是數(shù)值是不確定的,對于類型為其它類類型的數(shù)據(jù)成員,它會(huì)調(diào)用其它類類型的無參構(gòu)造函數(shù)完成初始化,對于數(shù)組型數(shù)據(jù)成員,會(huì)自動(dòng)執(zhí)行每個(gè)數(shù)組元素對象的構(gòu)造。類類型的數(shù)據(jù)成員,將在本章第7節(jié)講述。時(shí)鐘類無提供構(gòu)造函數(shù)時(shí),編譯器自動(dòng)合成無參構(gòu)造函數(shù),實(shí)際時(shí)鐘對象建立時(shí)調(diào)用系統(tǒng)合成的無參構(gòu)造函數(shù),實(shí)際效果并未完成初始化,所以顯示時(shí)結(jié)果具有不確定性。注意,類設(shè)計(jì)者提供任何構(gòu)造函數(shù)后,說明類對象狀態(tài)需要初始化,因此,C++規(guī)定編譯器不再提供自動(dòng)合成的構(gòu)造函數(shù)。類對象建立時(shí)如果無對應(yīng)構(gòu)造函數(shù),編譯將報(bào)錯(cuò)。計(jì)算機(jī)學(xué)院李衛(wèi)明C++提供了專門用于構(gòu)造函數(shù)的初始化列表機(jī)制,以冒號:開始,逗號間隔,指明類數(shù)據(jù)成員的初始化,上述時(shí)鐘類的構(gòu)造函數(shù)可改為如下形式,效果與前面一樣。CClock::CClock():m_iHour(0),m_iMinute(0),m_iSecond(0){}CClock::CClock(intiHour,intiMinute,intiSecond):m_iHour(iHour),m_iMinute(iMinute),m_iSecond(iSecond){}本章第7節(jié)中具有其它類類型的數(shù)據(jù)成員的構(gòu)造必須在初始化列表里顯式完成或隱式調(diào)用無參構(gòu)造函數(shù)完成,第5章具有繼承關(guān)系的類在初始化基類部分成員時(shí)也是這樣完成的,具體內(nèi)容在相應(yīng)章節(jié)介紹。構(gòu)造函數(shù)實(shí)際由初始化列表和構(gòu)造函數(shù)體兩部分組成,構(gòu)造函數(shù)體中語句實(shí)際進(jìn)行的是成員構(gòu)造完成后的重新改變或使用。計(jì)算機(jī)學(xué)院李衛(wèi)明C++11提供了支持對象初始化、委托構(gòu)造函數(shù)和數(shù)據(jù)成員聲明時(shí)初始化新機(jī)制。C++11提供了新的統(tǒng)一大括號形式初始化,構(gòu)造初始化列表里數(shù)據(jù)成員的構(gòu)造也可采用大括號代替小括號。上述例子中,定義時(shí)鐘類對象t1、t2、t3時(shí)可以采用如下語句:CClockt1{},t2{6,10,20},t3;t1、t3采用無參構(gòu)造函數(shù)構(gòu)造,效果相同,t2采用指定時(shí)間的構(gòu)造函數(shù)構(gòu)造。類似的,內(nèi)置數(shù)據(jù)類型變量也可以采用類似形式初始化。C++規(guī)定,內(nèi)置數(shù)據(jù)類型變量采用明確的構(gòu)造函數(shù)調(diào)用但沒有給實(shí)參時(shí),變量會(huì)被初始化為0,如下面變量定義語句,x4初始化為0,而x5沒有初始化:intx1=1,x2(2),x3{3},x4{},x5;計(jì)算機(jī)學(xué)院李衛(wèi)明2.3.6 C++11初始化新機(jī)制C++11支持類的一個(gè)構(gòu)造函數(shù)可以在構(gòu)造函數(shù)的初始化列表里委托類的其它構(gòu)造函數(shù)完成初始化。如前面時(shí)鐘類實(shí)現(xiàn)如下指定時(shí)間構(gòu)造函數(shù)后,無參構(gòu)造函數(shù)委托指定時(shí)間的構(gòu)造函數(shù)完成對象0:0:0狀態(tài)的構(gòu)造。即:CClock::CClock(intiHour,intiMinute,intiSecond):m_iHour{iHour},m_iMinute{iMinute},m_iSecond{iSecond}{}CClock::CClock():CClock(0,0,0){}計(jì)算機(jī)學(xué)院李衛(wèi)明C++11支持類數(shù)據(jù)成員定義時(shí)初始化,類聲明里可以用=或大括號形式初始化。如時(shí)鐘類的定義里,數(shù)據(jù)成員m_iHour、m_iMinute、m_iSecond可以采用下述方法初始化后,時(shí)鐘類無參構(gòu)造函數(shù)初始化列表里沒有指明的m_iMinute、m_iSecond構(gòu)造采用數(shù)據(jù)成員定義時(shí)初始化值,構(gòu)造函數(shù)初始化列表里指明的數(shù)據(jù)成員構(gòu)造放棄定義時(shí)初始化。時(shí)鐘類采用如下形式的數(shù)據(jù)成員初始化和無參構(gòu)造函數(shù)后,無參構(gòu)造時(shí)鐘對象的內(nèi)部時(shí)間就是12:0:0。classCClock{//類定義成員函數(shù)部分省略private:int_iHour=0,_iMinute=0,_iSecond{0};};CClock::CClock():m_iHour{12}{}計(jì)算機(jī)學(xué)院李衛(wèi)明類對象在建立時(shí)通過自動(dòng)調(diào)用構(gòu)造函數(shù)完成對象狀態(tài)的初始化,類對象消失時(shí)則會(huì)自動(dòng)調(diào)用類的析構(gòu)函數(shù),進(jìn)行掃尾處理,釋放對象占用的動(dòng)態(tài)分配內(nèi)存等資源。類的構(gòu)造函數(shù)可以有多個(gè),支持類對象的不同構(gòu)造方法,類的析構(gòu)函數(shù)只有一個(gè),名字為~類名,沒有參數(shù),析構(gòu)函數(shù)也沒有返回值和返回值類型。沒有定義析構(gòu)函數(shù)時(shí),編譯器自動(dòng)合成一個(gè)析構(gòu)函數(shù),完成逐個(gè)數(shù)據(jù)成員的析構(gòu)。內(nèi)置數(shù)據(jù)類型和指針類型的析構(gòu)無實(shí)際動(dòng)作,數(shù)組類型的數(shù)據(jù)成員會(huì)執(zhí)行每個(gè)數(shù)據(jù)元素類型對象的析構(gòu),類類型的數(shù)據(jù)成員會(huì)執(zhí)行相應(yīng)類的析構(gòu)函數(shù)。給出上述時(shí)鐘類析構(gòu)函數(shù)的定義,大家可以跟蹤測試下,測試程序里的每個(gè)時(shí)鐘對象是否執(zhí)行了析構(gòu)函數(shù)、何時(shí)執(zhí)行。CClock::~CClock(){cout<<“執(zhí)行時(shí)鐘類析構(gòu)函數(shù)”<<endl;}計(jì)算機(jī)學(xué)院李衛(wèi)明2.3.7析構(gòu)函數(shù)2.4 對象數(shù)組和動(dòng)態(tài)對象
2.4.1 對象數(shù)組C/C++可以定義元素類型為內(nèi)置數(shù)據(jù)類型數(shù)組一樣,C++可以定義元素類型為類類型的數(shù)組,稱為對象數(shù)組。所有數(shù)組大小必須是編譯時(shí)可確定大小的常量表達(dá)式,也就是數(shù)組大小是編譯時(shí)可確定值的正整數(shù),不可運(yùn)行時(shí)才確定或調(diào)整大小。對象數(shù)組建立時(shí)會(huì)為數(shù)組的每個(gè)元素對象自動(dòng)調(diào)用構(gòu)造函數(shù),數(shù)組撤銷時(shí)會(huì)為數(shù)組的每個(gè)元素對象調(diào)用析構(gòu)函數(shù)。數(shù)組元素連續(xù)存放,可以通過下標(biāo)訪問,也可以通過起始地址訪問,絕不可越界。下列語句建立了100個(gè)時(shí)鐘對象的數(shù)組。CClockA[100];計(jì)算機(jī)學(xué)院李衛(wèi)明2.4.2 對象指針和動(dòng)態(tài)生成對象C++提供了new、new[]和delete、delete[]運(yùn)算符,分別用于動(dòng)態(tài)分配單個(gè)對象、對象數(shù)組和動(dòng)態(tài)刪除單個(gè)對象、對象數(shù)組。動(dòng)態(tài)生成的對象或?qū)ο髷?shù)組可以采用指針管理,如下列語句分別動(dòng)態(tài)分配生成了1個(gè)無參構(gòu)造的時(shí)鐘對象、1個(gè)指定參數(shù)構(gòu)造的時(shí)鐘對象和一個(gè)由n個(gè)時(shí)鐘對象組成的數(shù)組,n可以是運(yùn)行動(dòng)態(tài)分配語句時(shí)確定值i的變量。intn=10;CClock*p1,*p2,*p3;p1=newCClock;p2=newCClock(6,10,20);//等同于p2=newCClock{6,10,20};p3=newCClock[n];動(dòng)態(tài)分配1個(gè)對象時(shí),先在堆上申請對象直接占用內(nèi)存空間,再在申請得到的內(nèi)存空間上執(zhí)行構(gòu)造函數(shù)。動(dòng)態(tài)分配對象數(shù)組時(shí),先在堆上申請n個(gè)對象的數(shù)組直接占用的連續(xù)內(nèi)存空間,再在申請得到的內(nèi)存空間上為每個(gè)對象分別執(zhí)行構(gòu)造函數(shù)。注意,如果類對象構(gòu)造時(shí)本身需要?jiǎng)討B(tài)分配,構(gòu)造函數(shù)過程中也會(huì)再次動(dòng)態(tài)申請空間,詳見第3章。如果申請過程失敗,與普通的動(dòng)態(tài)分配一樣,現(xiàn)代面向?qū)ο蟪绦蛟O(shè)計(jì)一般會(huì)拋出異常,采用異常機(jī)制處理,詳見第7章。計(jì)算機(jī)學(xué)院李衛(wèi)明動(dòng)態(tài)分配生成的對象位于堆空間,可跨函數(shù)傳遞對象指針,只有執(zhí)行刪除操作時(shí)才會(huì)撤銷動(dòng)態(tài)分配的對象。如果沒有執(zhí)行刪除操作,不會(huì)執(zhí)行對象類的析構(gòu)函數(shù)和釋放對象直接占用內(nèi)存空間,可能造成內(nèi)存泄漏。刪除操作有2種,分別對應(yīng)于new和new[],delete用于刪除單個(gè)對象,delete[]用于刪除對象數(shù)組,如下述語句分別刪除p1、p2所指對象和p3所指對象數(shù)組:deletep1;deletep2;delete[]p3;刪除單個(gè)對象時(shí),先執(zhí)行對象類的析構(gòu)函數(shù),再釋放對象直接占用空間。刪除對象數(shù)組時(shí)先執(zhí)行數(shù)組里每個(gè)對象的析構(gòu)函數(shù),再釋放對象數(shù)組直接占用的內(nèi)存空間。注意,刪除的對象指針必須是動(dòng)態(tài)分配得到的,而且同一個(gè)對象不可刪除2次,否則,后果嚴(yán)重。delete或delete[]運(yùn)算符后指針可以是空指針,效果相當(dāng)于無動(dòng)作。為防止多次刪除,不妨在刪除對象或?qū)ο髷?shù)組后將指針變量置為空指針nullptr。下列語句建立了具有100個(gè)元素的數(shù)組,每個(gè)數(shù)組元素是指向時(shí)鐘對象的指針變量。CClock*P[100];計(jì)算機(jī)學(xué)院李衛(wèi)明2.4.3 對象引用引用是被引用對象的別名,引用必須在建立時(shí)初始化。引用可以作為左值。被引用對象的類型可以是基本數(shù)據(jù)類型和指針類型,也可以是類類型。C++類的對象一般默認(rèn)可以直接復(fù)制和賦值,默認(rèn)的復(fù)制行為是逐個(gè)數(shù)據(jù)成員的復(fù)制,默認(rèn)的賦值行為是逐個(gè)數(shù)據(jù)成員的賦值。對于內(nèi)置數(shù)據(jù)類型的數(shù)據(jù)成員,復(fù)制和賦值的是數(shù)據(jù)成員內(nèi)部的數(shù)值,這對于沒有使用動(dòng)態(tài)分配的類來說是正確的行為。對于需要使用動(dòng)態(tài)分配的類來說,指針成員的復(fù)制和賦值,實(shí)際是指針變量的值,這可能會(huì)導(dǎo)致嚴(yán)重的問題,第3章專門講述這一問題及解決辦法。大型對象的復(fù)制和賦值會(huì)導(dǎo)致嚴(yán)重的性能開銷,傳遞引用比傳遞對象的指針更直觀、方便,大型對象的首選參數(shù)傳遞和返回方式是引用。如果需要在函數(shù)調(diào)用過程中確保實(shí)參對象不會(huì)被修改,可采用常引用的參數(shù)傳遞方式。C++程序中,函數(shù)返回值返回對象引用時(shí),必須確保被引用對象的存在,否則可能導(dǎo)致嚴(yán)重問題,因此,函數(shù)中不可返回局部對象的引用。局部對象采用傳值方式返回時(shí),編譯器內(nèi)部會(huì)在完成局部對象的復(fù)制后返回,不會(huì)導(dǎo)致問題。因此,后面樣例Ex2.11中設(shè)計(jì)和實(shí)現(xiàn)了集合類CSet,2個(gè)集合對象并運(yùn)算后返回新結(jié)果集對象,并運(yùn)算成員函數(shù)聲明為:CSetUnion(constCSet&rhs)const;計(jì)算機(jī)學(xué)院李衛(wèi)明2.4.4 this指針、類成員作用域和生存期普通類成員函數(shù)隱含this指針,指向當(dāng)前對象。C++保證每個(gè)對象至少占1個(gè)字節(jié)存儲空間,任一時(shí)刻,不同對象的地址不同。類成員作用域在該類定義內(nèi)和類成員函數(shù)定義內(nèi)有效,公有成員在類外可通過對象.成員或?qū)ο笾羔?>成員訪問。規(guī)范命名可以避免類數(shù)據(jù)成員與成員函數(shù)形參同名,類數(shù)據(jù)成員與成員函數(shù)形參同名時(shí),根據(jù)最小作用域原則,成員函數(shù)體內(nèi)同名對象默認(rèn)代表形參,如果需要訪問同名類數(shù)據(jù)成員,可以通過類名::成員或通過this->成員指定訪問類的成員。類成員作為所在對象的一部分,隨著所在對象生成而生成,隨著所在對象消失而消失。計(jì)算機(jī)學(xué)院李衛(wèi)明2.5 常用容器使用舉例本節(jié)介紹C++STL(StandardTemplateLibrary)標(biāo)準(zhǔn)模板庫提供的常用容器類和它們的常用接口。所謂容器是一種對象,可以容納和管理很多其它類型的對象,容器里存放的其它類型對象稱為容器里的元素。C++STL提供的容器類經(jīng)過精心設(shè)計(jì)、廣泛驗(yàn)證,具有接口良好、使用方便、效率高的特點(diǎn),現(xiàn)代C++程序設(shè)計(jì)應(yīng)該盡量選用標(biāo)準(zhǔn)庫提供的合適容器類,另一方面,這些容器類或容器類模板的設(shè)計(jì)和實(shí)現(xiàn)充分體現(xiàn)了C++面向?qū)ο蟪绦蛟O(shè)計(jì)的特點(diǎn),是學(xué)習(xí)C++面向?qū)ο蟪绦蛟O(shè)計(jì)非常好的樣例。為了使容器類更通用,C++標(biāo)準(zhǔn)庫以類模板的形式產(chǎn)生容器類。關(guān)于類模板知識,詳見第6章。本節(jié)主要以整形元素為例,舉例說明這些容器的常用用法,這些用法同樣適用于元素類型為其它內(nèi)置數(shù)據(jù)類型和其它類類型的情況。大家從掌握樣例里這些常用容器的常用接口函數(shù)使用出發(fā),其它常用接口函數(shù)的使用,會(huì)在后續(xù)相關(guān)章節(jié)有所補(bǔ)充,附錄中包含了本書相關(guān)容器的較完整接口介紹,STL其它容器和它們的更多接口介紹推薦查閱C++標(biāo)準(zhǔn)程序庫(第2版)。計(jì)算機(jī)學(xué)院李衛(wèi)明2.5.1 向量vector向量容器用于連續(xù)存放多個(gè)對象,主要存儲空間位于堆上,內(nèi)部封裝了動(dòng)態(tài)分配,具有可運(yùn)行時(shí)確定向量大小和運(yùn)行時(shí)擴(kuò)充向量功能。使用向量,可與訪問數(shù)組元素同樣效率隨機(jī)訪問向量里元素,比使用數(shù)組更方便、更靈活。標(biāo)準(zhǔn)庫向量類模板可產(chǎn)生整形向量類vector<int>,使用時(shí)需包含頭文件<vector>。計(jì)算機(jī)學(xué)院李衛(wèi)明//Ex2.31#include<iostream>2#include<vector>3usingnamespacestd;45intmain()6{7size_ti;8intn;9cin>>n;10vector<int>V1,V2(n);11V1.reserve(5);12V1.push_back(1);13V1.push_back(2);14V1.push_back(3);15V1.push_back(5);16V1.push_back(7);17cout<<V1.back()<<endl;18V1.pop_back();1920for(i=0;i<V2.size();++i)21cin>>V2[i];22for(i=0;i<V1.size();++i)23cout<<V1[i]<<'\t';24cout<<endl;25for(i=0;i<V2.size();++i)26cout<<V2[i]<<'\t';27cout<<endl;28}計(jì)算機(jī)學(xué)院李衛(wèi)明2.5.2 *鏈表list鏈表也是程序設(shè)計(jì)中常用容器之一。C++list鏈表容器內(nèi)元素存放在結(jié)點(diǎn)內(nèi),容器用雙鏈表管理,內(nèi)部封裝了動(dòng)態(tài)分配,主要存儲空間位于堆上,支持在任意位置插入、刪除、查找元素等操作,具有插入和刪除元素時(shí)無需像向量容器一樣搬動(dòng)元素的優(yōu)點(diǎn)。鏈表不支持下標(biāo)訪問,鏈表里元素不可像數(shù)組元素一樣快速隨機(jī)訪問,一般需要通過迭代器訪問。標(biāo)準(zhǔn)庫鏈表類模板可產(chǎn)生整形鏈表類list<int>,使用時(shí)需包含頭文件<list>。下面例題介紹了在鏈表對象2端操作鏈表和遍歷鏈表內(nèi)所有元素的方法,鏈表的大多數(shù)操作需要通過迭代器進(jìn)行,關(guān)于迭代器和迭代器訪問的更多知識將在第8章講述,關(guān)于鏈表容器的功能還可查閱附錄。計(jì)算機(jī)學(xué)院李衛(wèi)明//Ex2.41#include<iostream>2#include<list>3usingnamespacestd;45intmain()6{7list<int>lst1;8lst1.push_back(1);9lst1.push_front(-1);10lst1.push_back(2);11lst1.push_front(-2);12lst1.push_back(3);13lst1.push_front(-3);14lst1.push_back(5);15lst1.push_front(-5);16lst1.push_back(7);17lst1.push_front(-7);18cout<<"size:"<<lst1.size()<<endl;19cout<<"front:"<<lst1.front()<<endl;20lst1.pop_front();21cout<<"back:"<<lst1.back()<<endl;22lst1.pop_back();2324list<int>::iteratorit;25for(it=lst1.begin();it!=lst1.end();++it)26cout<<*it<<'\t';27cout<<endl;28}計(jì)算機(jī)學(xué)院李衛(wèi)明2.5.3 *雙端隊(duì)列deque與向量容器、鏈表容器一樣,雙端隊(duì)列容器也是常用容器之一。雙端容器里元素通常保存在多個(gè)分段的內(nèi)存區(qū)塊中,段內(nèi)連續(xù)、段間不需要連續(xù),C++雙端隊(duì)列容器支持在頭尾兩端快速添加、刪除元素,也支持通過下標(biāo)快速、隨機(jī)訪問容器內(nèi)元素。相對于向量容器,雙端隊(duì)列因?yàn)榉侄翁攸c(diǎn),在兩端添加、刪除元素時(shí),具有無需大量搬動(dòng)容器內(nèi)原有元素的優(yōu)點(diǎn);相對于鏈表容器,雙端隊(duì)列容器無需存放每個(gè)結(jié)點(diǎn)的前后結(jié)點(diǎn)指針,具有內(nèi)存使用率較高的優(yōu)點(diǎn),還可通過下標(biāo)較快速訪問容器內(nèi)元素。計(jì)算機(jī)學(xué)院李衛(wèi)明//Ex2.51#include<iostream>2#include<deque>3usingnamespacestd;45intmain()6{7deque<int>deque1;8deque1.push_back(1);9deque1.push_front(-1);10deque1.push_back(2);11deque1.push_front(-2);12deque1.push_back(3);13deque1.push_front(-3);14deque1.push_back(5);15deque1.push_front(-5);16deque1.push_back(7);17deque1.push_front(-7);18cout<<"size:"<<deque1.size()<<endl;19cout<<"front:"<<deque1.front()<<endl;20deque1.pop_front();21cout<<"back:"<<deque1.back()<<endl;22deque1.pop_back();2324deque<int>::iteratorit;25for(it=deque1.begin();it!=deque1.end();++it)26cout<<*it<<'\t';27cout<<endl;28size_ti;29for(i=0;i<deque1.size();++i)30cout<<deque1[i]<<'\t';31cout<<endl;32}計(jì)算機(jī)學(xué)院李衛(wèi)明2.5.4 字符串stringC++標(biāo)準(zhǔn)庫提供了字符串類string,使用時(shí)需包含頭文件<string>。字符串里面存放的是字符,可看作存放字符的特殊容器。字符串對象建立時(shí)可以是一個(gè)空串或具有指定字符串值。字符串類string對象可像整形變量一樣進(jìn)行輸入、輸出,字符串類具有返回長度的成員函數(shù)length,2個(gè)字符串類對象還可用運(yùn)算符==、!=、>=、<=、<、>進(jìn)行各類比較運(yùn)算,2個(gè)字符串對象可用+運(yùn)算符進(jìn)行連接運(yùn)算,返回一個(gè)新字符串對象,原字符串對象不變。字符串對象可復(fù)制和賦值,字符串對象可像訪問向量元素一樣,通過下標(biāo)訪問字符串內(nèi)字符,同樣,下標(biāo)必須有效,有效下標(biāo)范圍:0~length()-1。C++編譯器也可將字符串字面常量轉(zhuǎn)換為字符串對象進(jìn)一步參加運(yùn)算。關(guān)于字符串類的更多功能可參見附錄。計(jì)算機(jī)學(xué)院李衛(wèi)明//Ex2.61#include<iostream>2#include<string>3usingnamespacestd;45intmain()6{7size_ti;8stringstr1,str2,str3,str4("HelloWorld");//建立4個(gè)字符串對象
9cin>>str1;//輸入字符串對象
10cin>>str2;11cout<<str1<<endl;//輸出字符串對象
12cout<<str2<<endl;13str3=str1+str2;//字符串連接,結(jié)果賦值給str314cout<<str3<<endl;15if(str3=="HelloWorld")//字符串比較
16{17cout<<"EqualHelloWorld"<<endl;18}19else20cout<<"NotEqualHelloWorld"<<endl;21if(str3==str4)//字符串比較
22{23cout<<"Equal"<<str4<<endl;24}25else26cout<<"NotEqual"<<str4<<endl;27for(i=0;i<str3.length();++i)28if(str3[i]>='a'&&str3[i]<='z')29str3[i]=str3[i]-'a'+'A';//小寫字母轉(zhuǎn)成大寫字母
30cout<<endl<<"Afterchange:";31for(i=0;i<str3.length();++i)32cout<<str3[i];//采用單字母輸出
33cout<<endl<<"Afterchange:";34if(str3==str4)35{36cout<<"Equal"<<str4<<endl;37}38else39cout<<"NotEqual"<<str4<<endl;40stringstr;41getline(cin,str);//整行輸入作為字符串
42cout<<str<<endl;43}計(jì)算機(jī)學(xué)院李衛(wèi)明2.5.5 棧stack棧和隊(duì)列是程序設(shè)計(jì)中常用的2種特殊容器,棧具有后進(jìn)先出特點(diǎn),隊(duì)列具有先進(jìn)先出特點(diǎn)。C++STL里棧類模板是通過改造其它容器接口實(shí)現(xiàn)的,是一種容器適配器,關(guān)于容器適配器,詳見第8章。使用棧時(shí)需包含頭文件<stack>,使用隊(duì)列時(shí)需包含頭文件<queue>。使用棧類模板一樣可產(chǎn)生棧類。棧對象建立時(shí)調(diào)用無參構(gòu)造函數(shù),構(gòu)造一個(gè)空棧,棧還具有判空empty、入棧push、取棧頂top、出棧功能pop,還支持棧的復(fù)制和賦值。計(jì)算機(jī)學(xué)院李衛(wèi)明//Ex2.71#include<iostream>2#include<string>3#include<stack>4usingnamespacestd;56intmain()7{8stringstr;9stack<string>S1,S2;1011while(cin>>str)12{13if(!str.empty()&&str[0]>='A'&&str[0]<='Z')14S1.push(str);15else16S2.push(str);17}18while(!S1.empty())19{20cout<<S1.top()<<'\t';21S1.pop();22}23cout<<endl;24while(!S2.empty())25{26cout<<S2.top()<<'\t';27S2.pop();28}29cout<<endl;30}計(jì)算機(jī)學(xué)院李衛(wèi)明2.5.6 隊(duì)列queue正如前面所述,隊(duì)列是具有先進(jìn)先出特點(diǎn)的常用特殊容器,C++標(biāo)準(zhǔn)庫里隊(duì)列類模板也是通過改造其它容器接口實(shí)現(xiàn)的,是一種容器適配器。使用隊(duì)列時(shí),需包含頭文件<queue>。使用隊(duì)列類模板一樣可產(chǎn)生隊(duì)列類。隊(duì)列對象建立時(shí)調(diào)用無參構(gòu)造函數(shù),構(gòu)造一個(gè)空隊(duì)列。隊(duì)列具有判空empty、入隊(duì)列push、取隊(duì)列首元素front、出隊(duì)列功能pop,隊(duì)列還可復(fù)制和賦值。計(jì)算機(jī)學(xué)院李衛(wèi)明//Ex2.81#include<iostream>2#include<string>3#include<queue>4usingnamespacestd;56intmain()7{8stringstr;9queue<string>Q1,Q2;1011while(cin>>str)12{13if(!str.empty()&&str[0]>='A'&&str[0]<='Z')14Q1.push(str);15else16Q2.push(str);17}18while(!Q1.empty())19{20cout<<Q1.front()<<'\t';21Q1.pop();22}23cout<<endl;24while(!Q2.empty())25{26cout<<Q2.front()<<'\t';27Q2.pop();28}29cout<<endl;30}計(jì)算機(jī)學(xué)院李衛(wèi)明2.6 類的嵌套定義
2.6.1 類的嵌套定義特殊場合下,C++可以在一個(gè)類內(nèi)定義另一個(gè)內(nèi)部類,形成類的嵌套關(guān)系。內(nèi)部類可以像普通類一樣,在定義時(shí)直接實(shí)現(xiàn)內(nèi)部類成員函數(shù)。內(nèi)部類名是外部類的類型成員,可直接使用的有效范圍是外部類,在其它地方使用時(shí),需要在內(nèi)部類名前添加外部類名::,如下所示:外部類名::內(nèi)部類名內(nèi)部類成員函數(shù)在類定義外部實(shí)現(xiàn)時(shí)也需要在內(nèi)部類名前添加外部類名::,如下所示。外部類名::內(nèi)部類名::成員函數(shù)名(形參表)函數(shù)體使用內(nèi)部類的好處是表明內(nèi)部類和外部類的關(guān)系,內(nèi)部類名的作用域是外部類,多個(gè)外部類可以具有同名的內(nèi)部類,不會(huì)引起名字沖突。C++STL中大量使用的迭代器類就是以容器類的內(nèi)部類方式提供的,前面添加外部類名后,可以與普通類一樣使用和定義對象。下述語句分別定義了整形向量容器的迭代器it1、double鏈表容器的迭代器it2、字符串雙端隊(duì)列容器的迭代器it3:vector<int>::iteratorit1;list<double>::iteratorit2;deque<string>::iteratorit3;計(jì)算機(jī)學(xué)院李衛(wèi)明2.6.2 使用單鏈表實(shí)現(xiàn)的整形棧類簡單整形棧類的設(shè)計(jì)和實(shí)現(xiàn)。以單鏈表表示整形棧中元素組成的線性表,本節(jié)設(shè)計(jì)和實(shí)現(xiàn)的整形棧類具有與標(biāo)準(zhǔn)庫整形?;鞠嗤涌?,可以替換前面例子中使用的標(biāo)準(zhǔn)庫產(chǎn)生的整形棧。本例實(shí)現(xiàn)的整形棧類不支持棧對象的復(fù)制和賦值,關(guān)于使用動(dòng)態(tài)分配的類對象的復(fù)制和賦值,詳見第3章。棧的操作均在棧頂進(jìn)行,表示棧內(nèi)整形元素線性表的單鏈表無需頭結(jié)點(diǎn),而且,用鏈表首結(jié)點(diǎn)代表?xiàng)m斣?,鏈表的表尾部分代表?xiàng)5渍卧亍D2.5是單鏈表表示的整形??諚:途哂?個(gè)元素(20,1,3,5,10)棧狀態(tài)圖。
圖2.5單鏈表實(shí)現(xiàn)的整形棧狀態(tài)圖計(jì)算機(jī)學(xué)院李衛(wèi)明本例中單鏈表中結(jié)點(diǎn)類型Node采用整形棧類內(nèi)嵌結(jié)點(diǎn)類的方式,每個(gè)結(jié)點(diǎn)建立時(shí),包括動(dòng)態(tài)分配時(shí),調(diào)用結(jié)點(diǎn)類的構(gòu)造函數(shù),將指針域初始化為nullptr。棧對象建立時(shí)是一個(gè)空棧,整形棧具有構(gòu)造空棧的構(gòu)造函數(shù)。棧內(nèi)元素用動(dòng)態(tài)分配的結(jié)點(diǎn)表示,棧撤銷時(shí)應(yīng)該釋放所有動(dòng)態(tài)分配的空間,整形棧類實(shí)現(xiàn)析構(gòu)函數(shù)。棧需要具備入棧、判空、取棧頂元素、出棧功能,圖2.6是單鏈表表示的整形棧類圖。
圖2.6單鏈表實(shí)現(xiàn)的整形棧類圖本例中,實(shí)現(xiàn)棧類成員函數(shù)中用到的指針變量p是臨時(shí)變量,使用時(shí)在棧中分配,使用完后撤銷,不代表?xiàng)顟B(tài),不應(yīng)該作為類數(shù)據(jù)成員。計(jì)算機(jī)學(xué)院李衛(wèi)明//Ex2.91#include<iostream>2usingnamespacestd;34classCStack5{6public:78CStack():m_sp(nullptr)//構(gòu)造函數(shù)
9{}10~CStack() //析構(gòu)函數(shù)
11voidpush(intx); //入棧
12boolempty()const;//判???/p>
13inttop()const;//非空時(shí)取棧頂元素
14voidpop(); //非空時(shí)出棧
15private:16structNode//內(nèi)嵌結(jié)點(diǎn)類
17{18Node():next(nullptr){}//結(jié)點(diǎn)建立時(shí)指針域值為nullptr19intdata;20Node*next;21};22Node*m_sp;//鏈表首指針
23};2425CStack::~CStack()26{27//刪除所有結(jié)點(diǎn)
28while(m_sp!=nullptr)29{30Node*p=m_sp;//臨時(shí)指針變量p31m_sp=m_sp->next;32deletep;//刪除p所指結(jié)點(diǎn),刪除后不可使用該結(jié)點(diǎn)
33}34}3536voidCStack::push(intx)37{38Node*p=newNode;//動(dòng)態(tài)分配1個(gè)結(jié)點(diǎn)
39p->data=x;40p->next=m_sp;41m_sp=p;42}4344boolCStack::empty()const45{46return(m_sp==nullptr);47}
計(jì)算機(jī)學(xué)院李衛(wèi)明48intCStack::top()const49{50returnm_sp->data;51}5253voidCStack::pop()54{55Node*p=m_sp;56m_sp=p->next;57deletep;58}5960intmain()61{62CStackS1,S2;63intv,x;6465while(cin>>v>>x)66{67if(v==1)68S1.push(x);69else70S2.push(x);71}7273while(!S1.empty())74{75x=S1.top();76cout<<x<<"";77S1.pop();78}79cout<<endl;8081while(!S2.empty())82{83x=S2.top();84cout<<x<<"";85S2.pop();86}87cout<<endl;88}計(jì)算機(jī)學(xué)院李衛(wèi)明2.7 類類型的數(shù)據(jù)成員和has-a關(guān)系
2.7.1 類類型的數(shù)據(jù)成員和has-a關(guān)系在現(xiàn)實(shí)世界里,不同類型的物體間存在一種重要的關(guān)系,即整體和局部的關(guān)系,如一輛轎車一般具有4個(gè)輪胎,還有發(fā)動(dòng)機(jī)和傳動(dòng)系統(tǒng)等,轎車與輪胎、轎車與發(fā)動(dòng)機(jī)、轎車與傳動(dòng)系統(tǒng)間關(guān)系是非常緊密的整體和局部的關(guān)系,也稱為has-a關(guān)系。這里轎車與輪胎、發(fā)動(dòng)機(jī)、傳動(dòng)系統(tǒng)分別屬于不同的類別,這樣的關(guān)系在現(xiàn)實(shí)世界里比比皆是。反映在面向?qū)ο蟪绦蛟O(shè)計(jì)中,如果把轎車抽象成一個(gè)轎車類,輪胎抽象成輪胎類,發(fā)動(dòng)機(jī)抽象成發(fā)動(dòng)機(jī)類,傳動(dòng)系統(tǒng)抽象成傳動(dòng)系統(tǒng)類,一輛轎車可以由4個(gè)輪胎、發(fā)動(dòng)機(jī)、傳動(dòng)系統(tǒng)組成,一輛轎車是整體對象,輪胎、發(fā)動(dòng)機(jī)、傳動(dòng)系統(tǒng)是整體對象的一部分,具有不同的類型,是整體對象的子對象,構(gòu)成了一輛轎車,轎車的功能通過協(xié)調(diào)這些子對象的功能來實(shí)現(xiàn)。C++類對象的狀態(tài)通過類的數(shù)據(jù)成員值的組合來表示,類的數(shù)據(jù)成員類型不僅可以是內(nèi)置數(shù)據(jù)類型或內(nèi)置數(shù)據(jù)類型延伸出的指針型、數(shù)組型,還可以是其它類類型或延伸出的指針型和數(shù)組型。計(jì)算機(jī)學(xué)院李衛(wèi)明2.7.2 點(diǎn)類、圓類和它們的關(guān)系二維平面世界里點(diǎn)類CPoint,具有構(gòu)造、顯示、設(shè)置、相對移動(dòng)和絕大移動(dòng)、析構(gòu)功能。二維平面世界里的圓,以一個(gè)點(diǎn)為圓心,以某個(gè)數(shù)值為半徑,可具有構(gòu)造、顯示、相對移動(dòng)和絕對移動(dòng)、放大、析構(gòu)功能。圓的顯示、絕對移動(dòng)、相對移動(dòng)都是通過點(diǎn)的顯示、絕對移動(dòng)、相對移動(dòng)實(shí)現(xiàn),圓的構(gòu)造函數(shù)里顯式或隱式地調(diào)用了點(diǎn)的構(gòu)造函數(shù)。構(gòu)造函數(shù)里沒有顯式調(diào)用點(diǎn)類的構(gòu)造函數(shù)時(shí),編譯器自動(dòng)調(diào)用點(diǎn)類的無參構(gòu)造函數(shù),如果點(diǎn)類不提供無參構(gòu)造函數(shù),編譯將報(bào)錯(cuò)。圖2.7是表示其中的圓類CCircle、點(diǎn)類CPoint類圖和它們之間的組合關(guān)系UML圖。
圖2.7圓類、點(diǎn)類組合關(guān)系圖計(jì)算機(jī)學(xué)院李衛(wèi)明//Ex2.101#include<iostream>2usingnamespacestd;3classCPoint4{5public:6CPoint(intx=0,inty=0);7~CPoint();8voidShow()const;9voidRelativeMove(intx,inty);10voidMoveTo(intx,inty);11private:12intm_x,m_y;13};14CPoint::CPoint(intx,inty)15:m_x(x),m_y(y)16{17cout<<"constructpoint<"<<m_x<<','<<m_y<<'>'<<endl;18}19CPoint::~CPoint()20{21cout<<"destructpoint<"<<m_x<<','<<m_y<<'>'<<endl;22}23voidCPoint::Show()const24{25cout<<'<'<<m_x<<','<<m_y<<'>'<<endl;26}27voidCPoint::RelativeMove(intx,inty)28{29m_x+=x;30m_y+=y;31}32voidCPoint::MoveTo(intx,inty)33{34m_x=x;35m_y=y;36}37classCCircle38{39public:40CCircle();41CCircle(constCPoint&rhs,doubledRadius);42~CCircle();43voidScale(doubledScaleRatio);44voidS
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年智能防盜門安裝與系統(tǒng)集成服務(wù)協(xié)議3篇
- 2024技術(shù)支持協(xié)議書范本
- 2024版聘用合同勞動(dòng)合同
- 2025年度苯板銷售與產(chǎn)業(yè)鏈整合合同2篇
- 二零二五年度環(huán)保型廣告車租賃服務(wù)協(xié)議6篇
- 2024延期支付科研經(jīng)費(fèi)合同協(xié)議書3篇
- 2024昆明市二手房買賣合同及其空氣質(zhì)量保證協(xié)議
- 二零二五年金融衍生品交易合同公證協(xié)議3篇
- 二零二五年度賓館客房租賃合同解除協(xié)議2篇
- 武漢信息傳播職業(yè)技術(shù)學(xué)院《空間數(shù)據(jù)庫》2023-2024學(xué)年第一學(xué)期期末試卷
- 常用靜脈藥物溶媒的選擇
- 當(dāng)代西方文學(xué)理論知到智慧樹章節(jié)測試課后答案2024年秋武漢科技大學(xué)
- 2024年預(yù)制混凝土制品購銷協(xié)議3篇
- 2024-2030年中國高端私人會(huì)所市場競爭格局及投資經(jīng)營管理分析報(bào)告
- GA/T 1003-2024銀行自助服務(wù)亭技術(shù)規(guī)范
- 《消防設(shè)備操作使用》培訓(xùn)
- 新交際英語(2024)一年級上冊Unit 1~6全冊教案
- 2024年度跨境電商平臺運(yùn)營與孵化合同
- 2024年電動(dòng)汽車充電消費(fèi)者研究報(bào)告-2024-11-新能源
- 湖北省黃岡高級中學(xué)2025屆物理高一第一學(xué)期期末考試試題含解析
- 上海市徐匯中學(xué)2025屆物理高一第一學(xué)期期末學(xué)業(yè)水平測試試題含解析
評論
0/150
提交評論