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

下載本文檔

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

文檔簡介

第3章面向?qū)ο蟪绦蛟O(shè)計

3.1面向?qū)ο蟪绦蛟O(shè)計思想

3.1.1歷史回顧

1967年挪威計算中心的KistenNygaardW0leJohanDahl開發(fā)了Simula67

語言,它提供了比子程序更高一級的抽象和封裝,引入了數(shù)據(jù)抽象和類的概念,它被認(rèn)為是

第一個面向?qū)ο笳Z言。20世紀(jì)70年代初,PaloAlto研究中心的AlanKay所在的研

究小組開發(fā)出Smallta1k語言,之后又開發(fā)出Smalltalk-80,Smallta1k-80被認(rèn)

為是最純正的面向?qū)ο笳Z言,它對后來出現(xiàn)的面向?qū)ο笳Z言,如Object-C,C++,S

elf,Eiff1都產(chǎn)生了深遠的影響。隨著面向?qū)ο笳Z言的出現(xiàn),面向?qū)ο蟪绦蛟O(shè)計也就應(yīng)運

而生且得到迅速發(fā)展。之后,面向?qū)ο蟛粩嘞蚱渌A段滲透,1980年GradyRooch提出

了面向?qū)ο笤O(shè)計的概念,之后面向?qū)ο蠓治鲩_始。1985年,第一個商用面向?qū)ο髷?shù)據(jù)庫

問世。1990年以來,面向?qū)ο蠓治?、測試、度量和管理等研究都得到長足發(fā)展。

事實上,“對象”和“對象的屬性”這樣的概念可以追溯到20世紀(jì)50年代初,它們

一方面出現(xiàn)于關(guān)于人工智能的初期著作中。但是出現(xiàn)了面向?qū)ο笳Z言之后,面向?qū)ο笏枷?/p>

才得到了迅速的發(fā)展。過去的幾十年中,程序設(shè)計語言對抽象機制的支持限度不斷提高:從

機器語言到匯編語言,到高級語言,直到面向?qū)ο笳Z言。匯編語言出現(xiàn)后,程序員就避免

了直接使用0-1,而是運用符號來表達機器指令,從而更方便地編寫程序;當(dāng)程序規(guī)模繼續(xù)

增長的時候,出現(xiàn)了Fortran、C、Pascal等高級語言,這些高級語言使得編寫復(fù)雜的程

序變得容易,程序員們可以更好地對付日益增長的復(fù)雜性。但是,假如軟件系統(tǒng)達成一定

規(guī)模,即使應(yīng)用結(jié)構(gòu)化程序設(shè)計方法,局勢仍將變得不可控制。作為一種減少復(fù)雜性的工

具,面向?qū)ο笳Z言產(chǎn)生了,面向?qū)ο蟪绦蛟O(shè)計也隨之產(chǎn)生。

3.1.2什么是面向?qū)ο蟪绦蛟O(shè)計

一方面我們要了解的是,什么是面向?qū)ο蟮某绦蛟O(shè)計方法oOP(ObjectOriented

Programming),它與傳統(tǒng)的結(jié)構(gòu)化程序設(shè)計方法SP(StructureProgramming)

的重要區(qū)別是什么。

要弄清什么是OOP,則應(yīng)了解和回顧一下傳統(tǒng)的結(jié)構(gòu)化程序設(shè)計方法及其設(shè)計思想、

程序結(jié)構(gòu)與特點,以便比較對照兩者之間的差異,由此領(lǐng)略O(shè)OP對SP的繼承、豐富、發(fā)

展和突破。

1.結(jié)構(gòu)化程序設(shè)計思想

結(jié)構(gòu)化程序設(shè)計SP是60年代誕生的,以針對當(dāng)時爆發(fā)的所謂“軟件危機”的挑戰(zhàn),

而在70、80年代遍及全球成為所有軟件開發(fā)設(shè)計領(lǐng)域、每個程序員都廣為采用的傳統(tǒng)的

結(jié)構(gòu)化程序設(shè)計方法與技術(shù)的簡稱。它的產(chǎn)生和發(fā)展形成了現(xiàn)代軟件工程學(xué)的基礎(chǔ)。

SP的總的設(shè)計思緒是兩點:一是自頂向下,層次化;二是逐步求精,精細(xì)化。

其程序結(jié)構(gòu)是按功能劃分基本模塊為樹型結(jié)構(gòu),使模塊間的關(guān)系盡也許簡樸、獨立,并

從而單獨驗證模塊的對的性。每一模塊均由順序、選擇和循環(huán)三種基本結(jié)構(gòu)組合而成。綜

言之,此即所謂“模塊化”。

因此,SP的程序的基本特點是:

a.按層次組織模塊。(即戰(zhàn)略上劃分戰(zhàn)役)

b.每一模塊只有一個入口,一個出口。(每一戰(zhàn)役盡也許簡樸、明確)

c.代碼和數(shù)據(jù)分離實現(xiàn)。(戰(zhàn)術(shù)上程序=數(shù)據(jù)結(jié)構(gòu)+算法)

SP實現(xiàn)上述戰(zhàn)略戰(zhàn)術(shù)的具體方法和技術(shù)是:使用局部變量和子程序。

SP的優(yōu)點可以概括為:

a.子程序?qū)Τ绦蚱渌糠譀]有或盡也許少的連帶作用,從而為共享代碼奠定基礎(chǔ)。

b.由于SP方法的模塊化分解與功能抽象,自頂向下,分而治之的手段及技術(shù),從而能有效

地將一個復(fù)雜的、中大規(guī)模的程序系統(tǒng)的設(shè)計任務(wù)提成許多易于控制和解決、可獨立編程

的子任務(wù)、子程序模塊。

c.對于上述子程序或模塊中的每一個都有一個清楚的抽象界面,它只說明:相應(yīng)用程

序設(shè)計者來說只需了解它做什么(Whattodo),而不必說明:它如何去做(Howtodo)。

但從本質(zhì)上說,由Pascal和C這樣的程序設(shè)計推動的傳統(tǒng)的SP仍是一種面向數(shù)

據(jù)和過程的設(shè)計方法,它把數(shù)據(jù)和過程分離為互相獨立的實體,用數(shù)據(jù)代表問題空間中的

客體借以表達實際問題中的信息;程序代碼則體現(xiàn)用于解決加工這些數(shù)據(jù)的算法。

于是,程序員在編程時必須時刻考慮要解決的數(shù)據(jù)結(jié)構(gòu)和類型,對不同的數(shù)據(jù)格式(結(jié)

構(gòu)和類型)即使要作同樣的解決計算,或者對于相同的數(shù)據(jù)格式要作不同的解決都要編寫不

同的程序,可見,使用傳統(tǒng)SP方法設(shè)計出來的程序或系統(tǒng),其可食用的成分很少。另一方

面,當(dāng)把數(shù)據(jù)和代碼作為不同的分離體時,總存在著用錯誤的數(shù)據(jù)調(diào)用對的的程序,或用對

的的數(shù)據(jù)調(diào)用錯誤的程序的危險。因而,使數(shù)據(jù)與程序始終保持相容一致,已成為程序員的

一個沉重的承擔(dān)。這就是為什么在開發(fā)一個大型軟件的過程中,假如用戶在工程的中、后期

對數(shù)據(jù)格式或?qū)崿F(xiàn)方案提出任何改變請求時,變化摧毀了前面工作的一切,前功盡棄。

2.面向?qū)ο蟪绦蛟O(shè)計思想

為了克服和解決當(dāng)今許多大型軟件項目和系統(tǒng)設(shè)計都接近或達成了SP方法所難以控

制解決和適應(yīng)其變化的上述種種矛盾及問題而產(chǎn)生了OOP方法與技術(shù)。OOP吸取了SP

的一切優(yōu)點和長處,同時又正視和順應(yīng)現(xiàn)實世界由物質(zhì)和意識兩部分組成的這一普遍原理,

將其映射到對象的解空間就是:具體事物一一對象,抽象概念一一類;而一個對象無非就是

這樣一個實體,它具有一個名字標(biāo)記,并帶有自身的狀態(tài)(屬性)和自身的功能(行為或方

法)。世界上的所有事物(對象)就是如此奇妙地簡樸。這正是面向?qū)ο蠓椒ê图夹g(shù)所追求的

目的:將世界上的問題盡也許簡樸化。

事實上,用計算機求解的問題都是現(xiàn)實世界中的問題,它們無非都是由一些互相聯(lián)系的,

并處在不斷運動變化的事物(即對象)所組成。每個具體對象都可用兩個特性來把握:描

述事物靜態(tài)數(shù)據(jù)和可施于這些數(shù)據(jù)上的有限操作。也就是說,應(yīng)當(dāng)把數(shù)據(jù)結(jié)構(gòu)和對數(shù)據(jù)的操

作放在地起,作為一個互相依存不可分離的整體(即對象類)來解決(封裝、信息隱蔽、數(shù)

據(jù)抽象等)。并且要考慮不同事物即對象類之間的聯(lián)系(消息、通訊、協(xié)議等)和事物即對象

類的重用性和變化性(繼承、多態(tài)等),這才更符合客觀世界的本來面目。

概言之,OOP與SP不同,它除了包納了SP的一切優(yōu)特點與機制外,同時又是一個引

入若干強有力的、更能反映事物本質(zhì)的新概念、新機制,從而開創(chuàng)了一個程序新天地的強

人新方法。

OOP的基本原理是:用問題領(lǐng)域的模型來模擬現(xiàn)實世界,從而設(shè)計出盡也許直接、自然

地表達問題求解方法的軟件,這樣的軟件系統(tǒng)由對象組成,而對象則是完整反映客觀世界

事物具有不可分割的靜態(tài)屬性(數(shù)據(jù)結(jié)構(gòu))與動態(tài)行為(方法)的,并且它們是既有聯(lián)系又有

變化發(fā)展的實體。

OOP方法所涉及的新概念,在理論上最具一般性的相應(yīng)物及其描述如下等等:

a.對象一一對客觀世界事物的表達或描述,世界上任何具體事物均可稱為對象。

b.類一一是一組對象的抽象定義(抽象概念、抽象數(shù)據(jù)類型)

c.方法相應(yīng)于對象的功能。

d.消息一一對象之間通訊的途徑。

e.繼承一一對象間具有相同性和差異變化的關(guān)系。

基于以上概念,面向?qū)ο缶统闪艘粋€作為現(xiàn)實世界映射的封閉的縮微世界,一個對象具

有自身的屬性(私有數(shù)據(jù)成員)和可認(rèn)為自己或別人工作的功能(方法、操作或稱成員函數(shù)),

它能通過發(fā)送消息與其它對象進行通訊,協(xié)同完畢任務(wù)。

OOP并不是用一兩句話就可以精擬定義描述清楚的一套方法與技術(shù),然而在這里,我

們還是非形式化地、籠統(tǒng)地說明和描述一下OOP的概念:OOP是SP、信息掩蔽、知識

表達、并行解決領(lǐng)域等概念的繼承和發(fā)展。OOP的特點是把系統(tǒng)設(shè)計成將所需規(guī)定解的問

題分解成一些對象及對象間傳遞消息的符合客觀世界規(guī)律的自然過程。OOP方法使程序

員擺脫具體的數(shù)據(jù)格式和過程的束縛,將精力集中到對要解決的對象的設(shè)計和研究上,從而

大大減少了軟件開發(fā)的復(fù)雜度。OOP涉及了功能抽象的抽象數(shù)據(jù)、信息隱蔽即封裝等機理,

使對象的內(nèi)部實現(xiàn)與外界隔離,從而提供了更抱負(fù)的模塊化機制,大大減少了程序間的互相

干擾和副作用。OOP的抽象數(shù)據(jù)類型一一對象類及繼承,則為我們提供了抱負(fù)的高可重

用性的軟件成份和機制。

此外,在人工智能領(lǐng)域中,若用OOP方法表達知識,則更接近于自然的客觀世界的知

識表達和結(jié)識論,因而不僅能表達描述非常復(fù)雜的客觀事物和知識,并且具有模塊性強、

結(jié)構(gòu)化限度高,便于分層實現(xiàn),有助于實際開發(fā)和維護。因此OOP方法和技術(shù)的優(yōu)特點將

非常適合知識解決、知識庫、專家系統(tǒng)等人工智能領(lǐng)域和數(shù)據(jù)庫、CAD、圖形解決(多

媒體)、系統(tǒng)模擬與構(gòu)造等大型復(fù)雜軟件工程化開發(fā)。

3.1.3面向?qū)ο蟪绦蛟O(shè)計語言

一個語言要稱為面向?qū)ο笳Z言必須支持幾個重要面向?qū)ο蟮母拍睢8鶕?jù)支持限度的不

同,通常所說的面向?qū)ο笳Z言可以提成兩類:基于對象的語言,面向?qū)ο蟮恼Z言。

基于對象的語言僅支持類和對象,而面向?qū)ο蟮恼Z言支持的概念涉及:類與對象、繼

承、多態(tài)。舉例來說,Add就是個典型的基于對象的語言,由丁它不支持繼承、多態(tài),此外

其他基于對象的語言尚有A1phard、CLU、Euclid>Modulao面向?qū)ο蟮恼Z言中一部

分是新發(fā)明的語言,如Smalltalk、Java,這些語言自身往往吸取了其他語言的精華,

而又盡量剔除他們的局限性,因此面向?qū)ο蟮奶匦蕴貏e明顯,充滿了蓬勃的生機;此外一

些則是對現(xiàn)有的語言進行改造,增長面向?qū)ο蟮奶匦匝莼鴣淼?。如由Pascal發(fā)展而來

的ObjectPasca1,由C發(fā)展而來的Objective-C,C++,由Ada發(fā)展而來的Ada9

5等,這些語言保存著對原有語言的兼容,并不是純粹的面向?qū)ο笳Z言,但由于其前身往往

是有一定影響的語言,因此這些語言仍然寶刀不老,在程序設(shè)計語言中占有十分重要的地

位。

C++語言及環(huán)境中的OOP有五個最基本概念,這五個基本概念術(shù)語是構(gòu)成整個C++

面向?qū)ο蠓椒ㄅc技術(shù)的柱石。它便是:

a.對象(Object)

b.消息(Message)

c.方法(Method)

d.類(C1ass)

e.繼承(Inheritenee)

下面我們將分別介紹它們的含義、組成和性質(zhì)。

1.對象

什么是對象?對象是私有數(shù)據(jù)及可以對這些數(shù)據(jù)施加的操作結(jié)合在一起所構(gòu)成的獨

立實體。即一個對象基本上涉及兩個重要部分:記載對象內(nèi)部狀態(tài)的數(shù)據(jù)和表現(xiàn)對象活動

與功能的程序。

從傳統(tǒng)的SP觀點來看,數(shù)據(jù)和解決它們的代碼是兩個不同的獨立實體,它們之間的

對的聯(lián)系、選擇和匹配需要應(yīng)用系統(tǒng)的設(shè)計者時刻考慮。而OOP中,一個對象則是由私

有數(shù)據(jù)和其上的一組操作代碼組成的一個統(tǒng)一體。請看如下示意圖:

對象的動作取決于發(fā)送給該對象的消息表達式,消息告訴對象規(guī)定完畢的功能,并激活

該功能,這意味著對象具有自動“知道”如何完畢相應(yīng)操作代碼的“智能”選擇機制,正是

這一機制把sP中應(yīng)用系統(tǒng)程序員作出的選擇操作數(shù)據(jù)與相應(yīng)操作函數(shù)代碼匹配的承擔(dān)轉(zhuǎn)

移給了系統(tǒng)設(shè)計者。

上述所謂的“智能化”的選擇機制并不神秘,只但是是在對象的操作(過程或函數(shù))

表中對消息操作名進行按名搜索而已,相應(yīng)C++來說,執(zhí)行一個消息表達式就是觸發(fā)選擇機

制在相應(yīng)對象的調(diào)度表(內(nèi)存控制塊)中進行搜索,找到后便轉(zhuǎn)向相應(yīng)于該消息的成員函數(shù)

代碼中運營。

事實上,除了上述選擇匹配機制是新東西外,下面這些術(shù)語的含義和傳統(tǒng)的SP相應(yīng)名

詞及說明是相以相應(yīng)的:

對象——內(nèi)存中的數(shù)據(jù)塊

對象標(biāo)記符一一指向上述數(shù)據(jù)的指針

向?qū)ο蟀l(fā)送消息一一使成員函數(shù)作用于數(shù)據(jù)

在OOP中,數(shù)據(jù)和代碼是緊密結(jié)合在一起的計算機中的一內(nèi)存分塊。但局部于該對

象中的數(shù)據(jù)只可以由對象中的代制塊(成員函數(shù))來訪問,即數(shù)據(jù)是對象私有的(受保護的),

不能被其它對象影響和修改。簡樸地說,一個對象從不關(guān)心其它對象的內(nèi)部細(xì)節(jié),而只關(guān)心

它自己,對象之間的通訊只是以“做什么”的消息發(fā)送為契機,并且認(rèn)為接受消息的對象是

知道如何去做的。

對象可以非常簡樸,也可以十分復(fù)雜。通常復(fù)雜對象由簡樸的對象層層嵌套組合而成。

此后我們將從C++程序?qū)嵗锌吹?,對象形式上只是系統(tǒng)程序員、應(yīng)用程序員或用戶定

義的“類”這種數(shù)據(jù)結(jié)構(gòu)類型的變量,當(dāng)我們定義一個對象,就已發(fā)明出了一種新的抽象

數(shù)據(jù)類型。對象可以說是構(gòu)成和支撐整個OOP最重要的細(xì)胞與基石。除了上述基本組成、

關(guān)系和機理特性外,對象尚有以下性質(zhì)和優(yōu)點:

a.模塊獨立性。邏輯上看,一個對象是獨立存在的模塊,從外部看這模塊,只需了解它

具有哪些功能,至于它如何實現(xiàn)這些功能和使用哪些局部數(shù)據(jù)來完畢它們的細(xì)節(jié)則“隱蔽”

在模塊內(nèi)部。這意味著模塊內(nèi)部狀態(tài)不受外界干擾改變,也不會殃及到其它模塊。即模塊

間依賴性極小或幾乎沒有;各模塊可獨立為系統(tǒng)組合選用,也可被程序員重用,而不必緊張

波及或破壞別的模塊。

b.動態(tài)連接性。客觀世界中各式各樣的對象,并不是孤立存在的,正是它們之間的互相

作用、聯(lián)系和連接,才構(gòu)成了世間各種不同的系統(tǒng)。同時,在OOP中,通過消息(傳送)激

活機制,把對象之間動態(tài)聯(lián)系連接起來,便稱為對象的動態(tài)連接性,

c.易維護性。由于對象的功能被“隱蔽”和好象被一層封裝殼保護在對象內(nèi)部,故無

論是修改,還是功能完善以及實現(xiàn)的細(xì)節(jié)都被囿于該對象內(nèi)部,不會播及到外部去,這增長

了對象和整個系統(tǒng)的易維護性。

2.消息

什么是消息?消息是規(guī)定某個對象執(zhí)行其中某個功能操作的規(guī)格說明。

通俗地講,OOP中的術(shù)語“消息”只但是是現(xiàn)實世界中的“請求”、“命令”等平常生

活用語的同義詞。

通常,00P的一條消息由選擇器(“消息操作”或“消息名”)及若干變元(0個或多

個實參)和接受消息的對象三個部分組成。

從程序設(shè)計語言的角度出發(fā)來說,除前面曾經(jīng)提到過的消息具有提供(激活)對象的動

態(tài)選擇機制外,消息表達式從形式上看類似于普通的函數(shù)調(diào)用。

如代碼:

switch(message)

(

caseW_LBUTTONDOWN;//鼠標(biāo)左按鈕被按下

break;

caseWM_LBUTTONUP;//鼠標(biāo)左按鈕被放開

break;

)

一般,我們把發(fā)送消息的對象稱為發(fā)送者,接受消息的對象稱為接受者。對象間的聯(lián)

系,只能通過傳送消息即執(zhí)行消息表達式來進行。對象也只有在收到消息時,才被激活,

補激活的對象的代碼將知道如何去進行操作它的私有數(shù)據(jù),以完畢所發(fā)送的消息規(guī)定的功

能。消息發(fā)送不考慮具體的接受者,對象可以響應(yīng),也可以不響應(yīng)。

3.方法

什么是方法?OOP中的術(shù)語“方法”相應(yīng)于對象的能力,即它是實現(xiàn)對象所具有的功

能操作的代碼段,是響應(yīng)消息的“方法”。

C++中,方法即是類中定義的成員函數(shù),它只但是是該類對象所能執(zhí)行的操作的算法

實現(xiàn)而己。

方法與消息是相應(yīng)的,每當(dāng)對象收到一個消息,它除了能用“智能化”的選擇機制知

道和決定應(yīng)當(dāng)去做什么(Whattodo)外,還要知道和決定該如何做(Howtodo)0

而方法正是與對象相連決定怎么做的的操作執(zhí)行代碼。

4.類

什么是類?類是對一組對象的抽象歸納概括,確切地說,類是對一組具有相同數(shù)據(jù)成員

和相同操作成員的對象的定義和說明。而每個對象都是某個類的一個具體實例。

在OOP中,每個對象由一個類來定義或說明,類可以看作生產(chǎn)具有相同屬性和行為方

式對象的模板。類或分類就是所謂“物以類聚,人以群分”的意思,“類”就是具有相似性

質(zhì)的事物的同類特性的集中。簡言之,按照對象的相似性,我們把對象提成一些類和子類,

故相似對象的集合即稱為類。對C++程序員而言,類事實上是一種對象類型。它描述屬于該

類型的具有相同結(jié)構(gòu)和功能的對象的一般性質(zhì)。而結(jié)構(gòu)類型則是只有將相關(guān)信息(僅只是

不同類型的數(shù)據(jù)集)集中在一起的一個C的變量集。

從理論上講,類(class)是一組同類對象的抽象,它將該種對象的共同特性,涉

及操作特性和存儲特性都集中封裝起來。由屬于此類的對象共享。例如,討論食肉動物時,

我們并不只是特指老虎利獅子,而只是抽象出它們的共同特性:比如喜歡吃肉。更具體地,

又如:若為屏幕上的點設(shè)計一個類如下:

classpoint

(

x,y;

new();

deletc();

move();

highlight();

}

則可以說明point類的對象如:

pointa(100,50),b(30,60);

piont中定義的數(shù)據(jù)是抽象數(shù)據(jù)類型,而對象a,b中的數(shù)據(jù)則是對象相應(yīng)著內(nèi)存中

的具體數(shù)據(jù)單元拷貝塊,以其初始化時的具體值和存儲于不同單元塊而區(qū)分不同的對象。

5.繼承

什么是繼承?繼承是對象類間的一種相關(guān)關(guān)系,并具有以下關(guān)鍵內(nèi)容:

a.類間的共享的特性(涉及共享程序代碼和數(shù)據(jù))。

b.類間的細(xì)微區(qū)別或新增部分。

c.類間的層次結(jié)構(gòu)。

繼承機制既是一個對象類就獲得另一個對象類特性的過程,也是一個以分層結(jié)構(gòu)組織、

構(gòu)造和重用類的工具。它是解決客觀對象“相似又不同”的方法。

具體地講,若類B繼承了類A,則屬于類B中的對象便具有類A的一切性質(zhì)和功能。

我們稱A為基類或父類,而稱B為A的派生類或子類。因此,要描述或構(gòu)造一個新類B,只

須去繼承一個與之有共同特性的父類A,然后描述與父類不同的少量特性(即增長一些新的

數(shù)據(jù)成員或成員函數(shù))即可。

繼承機制有以下幾個優(yōu)特點:

a.能清楚體現(xiàn)相似類間的層次結(jié)構(gòu)關(guān)系。

b.能減少代碼和數(shù)據(jù)的反復(fù)冗余度,增強程序的重用性。

c.能通過增強一致性來減少模塊間的接口和界面,增強程序的易維護性。

d.繼承是能自動傳播代碼的有力工具。

e.繼承還是在一些比較一般的類的基礎(chǔ)上構(gòu)造、建立和擴充新類的最有效的手段。

假如沒有繼承概念的支持,則OOP中所有的類就象一盤各自為政、彼此獨立的散沙,

每次軟件開發(fā)都要從“一無所有”開始。

C++中,除了一般OOP方法的樹型層次結(jié)構(gòu)的單一繼承外,還支持多重繼承。對單一

繼承,每個子類只能有一個父類,而對多重繼承,每個子類則可以有多個父類。

3.1.4面向?qū)ο蟪绦蛟O(shè)計的優(yōu)點

面向?qū)ο蟪霈F(xiàn)以前"結(jié)構(gòu)化程序設(shè)計是程序設(shè)計的主流,結(jié)構(gòu)化程序設(shè)計又稱為面向

過程的程序設(shè)計。在面向過程程序設(shè)計中,問題被看作一系列需要完畢的任務(wù),函數(shù)(在

此泛指例程、函數(shù)、過程)用于完畢這些任務(wù),解決問題的焦點臬中于函數(shù)V其中函數(shù)是

面向過程的,即它關(guān)注如何根據(jù)規(guī)定的條件完畢指定的任務(wù)。

在多函數(shù)程序中,許多重要的數(shù)據(jù)被放置在全局?jǐn)?shù)據(jù)區(qū),這樣它們可以被所有的函數(shù)

訪問。每個函數(shù)都可以具有它們自己的局部數(shù)據(jù)。下圖顯示了一個面向過程程序中函數(shù)和

數(shù)據(jù)的關(guān)系。

這種結(jié)構(gòu)很容易導(dǎo)致全局?jǐn)?shù)據(jù)在無意中被其他函數(shù)改動,因而程序的對的性不易保

證。面向?qū)ο蟪绦蛟O(shè)計的出發(fā)點之一就是填補面向過程程序設(shè)計口的一些缺陷:對象是程

序的基本元素,它將數(shù)據(jù)和操作緊密地連結(jié)在一起,并保護數(shù)據(jù)不會被外界的函數(shù)意外地

改變。下圖顯示了一個面向?qū)ο蟪绦蛑袑ο笈c函數(shù)和數(shù)據(jù)的關(guān)系。

比較面向?qū)ο蟪绦蛟O(shè)計和面向過程程序設(shè)計,還可以得到面向?qū)ο蟪绦蛟O(shè)計的其他優(yōu)

占?

⑴數(shù)據(jù)抽象的概念可以在保持外部接口不變的情況下改變內(nèi)部實現(xiàn),從而減少甚至

避免對外界的干擾;

⑵通過繼承大幅減少冗余的代碼,并可以方便地擴展現(xiàn)有代碼,提高編碼效率,也減

低了犯錯概率,減少軟件維護的難度;

⑶結(jié)合面向?qū)ο蠓治觥⒚嫦驅(qū)ο笤O(shè)計,允許將問題域中的對象直接映射到程序中,減

少軟件開發(fā)過程中中間環(huán)節(jié)的轉(zhuǎn)換過程;

(4)通過對對象的辨別、劃分可以將軟件系統(tǒng)分割為若干相對為獨立的部分,在一定

限度上更便于控制軟件復(fù)雜度;

⑸以對象為中心的設(shè)計可以幫助開發(fā)人員從靜態(tài)(屬性)和動態(tài)(方法)兩個方面把握

問題,從而更好地實現(xiàn)系統(tǒng);

(6)通過對象的聚合、聯(lián)合可以在保證封裝與抽象的原則下實現(xiàn)對象在內(nèi)在結(jié)構(gòu)以及

外在功能上的擴充,從而實現(xiàn)對象由低到高的升級。

3.1.5面向?qū)ο蟪绦蛟O(shè)計重要特性

面向?qū)ο蟪绦蛟O(shè)計重要特性有三個:繼承性、封裝性和多態(tài)性。

1.繼承性

繼承性在上面己作介紹,不再反復(fù)。

2.封裝性

OOP中的封裝性是一種信息掩蔽技術(shù),它使系統(tǒng)設(shè)計員可以清楚地標(biāo)明他們所提供的

服務(wù)界面,用戶和應(yīng)用程序員則只看得見對象提供的操作功能(即封裝面上的信息),看

不到其中的數(shù)據(jù)或操作代碼細(xì)節(jié)。從用戶或應(yīng)用程序員的角度講:對象提供了一組服務(wù),

而服務(wù)的具體實現(xiàn)(即對象的內(nèi)部)卻對用戶屏蔽。如下圖所示:

從用戶和系統(tǒng)設(shè)計者看封裝,用戶只能看見對象提供的服務(wù),而看不到服務(wù)的具體實

現(xiàn),只有系統(tǒng)設(shè)計者才干看見封閉在對象中數(shù)據(jù)及其過程。

對象的這一封裝機制的目的在于將對象的設(shè)計者和使用者分開,使用者不必知道對象

行為實現(xiàn)的細(xì)節(jié),只須用設(shè)計者提供的消息命令對象去做就行了。

總之,我們可以這樣來定義封裝:

a.一個清楚的邊界。對象的所有私有數(shù)據(jù)、內(nèi)部程序即方法(成員函數(shù))細(xì)節(jié)被囿定

在這個邊界內(nèi)。

b.一個接口。這個接口描述了對象之間的互相作用,請求和響應(yīng),它就是消息。

c.對象內(nèi)部實現(xiàn)代碼受到封裝殼的保護,其它對象不能直接修改本對象擁有的(私有

的)數(shù)據(jù)和代碼,只有通過本對象類的內(nèi)部代碼(成員函數(shù))來修改。

這就是OOP中對象的封裝性。

3.多態(tài)性

OOP支持多態(tài)性,它指的是相同的函數(shù)調(diào)用,被不同的對象接受時,可導(dǎo)致不同的行為。

運用多態(tài)性,我們可以把函數(shù)的不同的實現(xiàn)細(xì)節(jié)留給接受函數(shù)調(diào)用的對象,而程序中則用

同一函數(shù)名進行一般形式的調(diào)用。例如,消息函數(shù)調(diào)用Print()被發(fā)送到一圖形對象時和

將其發(fā)送到一正文對象時的結(jié)果肯定不同樣。

例如,有三個函數(shù):

abs()返回整數(shù)絕對值

1abs()返回long的絕對值

fabs()返回double的絕對值

盡管這三個函數(shù)執(zhí)行幾乎相同的操作,在SP中,須用三個不同的函數(shù)說明及調(diào)來表達

和使用它們,即大同小異的函數(shù)也必須有不同的函數(shù)名。于是,雖然僅只是一個求絕對值

的運算行為,程序員必須至少記住三件事(三個函數(shù))。

在C++中,則改變了這一傳統(tǒng)做法,可以用一個名字來表達和訪問這三個函數(shù)而不會

出現(xiàn)混亂。即如下:

#include<iostream.h>

intabs(inti){returni<0?-i:i;}

doubleabs(doubled){returnd<0?—d:d;}

longabs(long1){return1<0?-1:1;}

main()

cout<<abs(—10)<<“\n";

cout<<abs(-11.0)?“\n";

cout<<abs(-9L)<<"\n"

它們是不同的函數(shù),卻使用同一名字abs,當(dāng)程序中調(diào)用abs時,OOP編譯器會根據(jù)自

變量類型自動錄找對的的那個函數(shù)進行運算,這就將要記住的三件事減少為只須記住一件

事了,從應(yīng)用的角度來看,就好象一個函數(shù)支持三種不同的運算(功能)同樣,這就是函數(shù)

的多態(tài)性。

除以上三大特性之外,面向?qū)ο蟪绦蛟O(shè)計還具有動態(tài)連接、消息驅(qū)動等特點。

所謂連接,是把例程地址送給例程調(diào)用者的過程。在運營前的編譯時便以目的代碼的

形式與系統(tǒng)完畢連接稱為靜態(tài)連接,而在運營時進行上述連接的則稱為動態(tài)連接。

傳統(tǒng)的C僅支持靜態(tài)連接,而面向?qū)ο蟮某绦蛟O(shè)計語言在其實現(xiàn)中使用了動態(tài)編譯技

術(shù),因而允許以目的代碼的形式在運營過程中才與系統(tǒng)進行連接。這使得系統(tǒng)的靈活性和

方便性大大增強。

OOP中的消息驅(qū)動機制不同于SP中的子程序調(diào)用,這是由于,子程序調(diào)用者與被調(diào)用

者有控制與被控制的關(guān)系,且凡調(diào)用必須有返回。而消息驅(qū)動則是當(dāng)一個對象想激活另一

個對象的某個功能時,它把請求以消息的形式傳送給接受者就算了事,至于接受對象如何

行動,如何解決該消息,完全是接受者自行決定的私事,其行為既不受發(fā)送者的控制,也不

一定有求必應(yīng)和必有返回。

下圖給出一個解決鍵盤輸入的消息驅(qū)動過程:

Windows

注意,上述過程中,每個應(yīng)用程序?qū)⒂斜粍?chuàng)建的一個相應(yīng)的應(yīng)用程序隊列。

3.1.7面向?qū)ο笤O(shè)計方法的特點和面臨的問題

面向?qū)ο笤O(shè)計方法以對象為基礎(chǔ),運用特定的軟件工具直接完畢從對象客體的描述到

軟件結(jié)構(gòu)之間的轉(zhuǎn)換。這是面向?qū)ο笤O(shè)計方法最重要的特點和成就。面向?qū)ο笤O(shè)計方法的

應(yīng)用解決了傳統(tǒng)結(jié)構(gòu)化開發(fā)方法中客觀世界描述工具與軟件結(jié)構(gòu)的不一致性問題,縮短了

開發(fā)周期,解決了從分析和設(shè)計到軟件模塊結(jié)構(gòu)之間多次轉(zhuǎn)換映射的繁雜過程,是一種很

有發(fā)展前程的系統(tǒng)開發(fā)方法。

但是同原型方法同樣,面向?qū)ο笤O(shè)計方法需要一定的軟件基礎(chǔ)支持才可以應(yīng)用,此外

在大型的MIS開發(fā)中假如不經(jīng)自頂向下的整體劃分,而是一開始就自底向上的采用面向?qū)?/p>

象設(shè)計方法開發(fā)系統(tǒng),同樣也會導(dǎo)致系統(tǒng)結(jié)構(gòu)不合理、各部分關(guān)系失調(diào)等問題。所以面向

對象設(shè)計方法和結(jié)構(gòu)化方法目前仍是兩種在系統(tǒng)開發(fā)領(lǐng)域互相依存的、不可替代的方法。

3.2類和對象

3.2.1類和對象概述

1.類和對象的聲明

在C程序設(shè)計中我們學(xué)習(xí)過結(jié)構(gòu)體,它的掌握非常重要,重要在哪里呢?重要在結(jié)構(gòu)體

和類有相同的特性,但又有很大的區(qū)別,類是構(gòu)成面向?qū)ο缶幊痰幕A(chǔ),但它是和結(jié)構(gòu)體

有著極其密切的關(guān)系。

我們在C語言中創(chuàng)建一個結(jié)構(gòu)體我們使用如下方法:

structtest

(

private:

intnumber;

public:

floatsocre;

};

類的創(chuàng)建方式和結(jié)構(gòu)體幾乎同樣,看如下的代碼:

classtest

(

private:

intnumber;

public:

floatsocre;

pub1ic:

intrp()

(

returnnumber;

)

voidsetnum(inta)

{

number=a;

)

);

但是大家注意到?jīng)]有,標(biāo)準(zhǔn)C中是不允許在結(jié)構(gòu)體中聲明函數(shù)的,但C++中的類可以,

這一點就和C有了本質(zhì)的區(qū)別,很好的體現(xiàn)了C++面向?qū)ο蟮奶攸c!

過去的C語言是一種非面向去象的語言,它的特性是:程序二算法+數(shù)據(jù)結(jié)構(gòu)。但C++

的特性是:對象=算法+數(shù)據(jù)結(jié)構(gòu);程序:對象+對象+對象+對象+........所以根據(jù)這一

特性,我們在定義一個自己定義的結(jié)構(gòu)體變量的時候。這個變量就應(yīng)當(dāng)是叫做對象或者叫

實例。

例如:

testa;

那么a就是test結(jié)構(gòu)的一個對象(實例),test結(jié)構(gòu)體內(nèi)的成員可以叫做是分量,例

如:

a.socre=10.1f;

那么number就是test結(jié)構(gòu)的對象a的分量(或者叫數(shù)據(jù)成員,或者叫屬性)sc。r

e;

在C語言中結(jié)構(gòu)體中的各成員他們的默認(rèn)存儲控制是public而C++中類的默認(rèn)存

儲控制是private,所以在類中的成員假如需要外部掉用一定要加上關(guān)鍵字public聲明

成公有類型,這一特性同樣使用于類中的成員函數(shù),函數(shù)的操作方式和普通函數(shù)差別并不

大。

例如上面的例子中的rp()成員函數(shù),我們假如有如下定義:

testa;

調(diào)用rp()就應(yīng)當(dāng)寫成:

a.rp();

成員函數(shù)的調(diào)用和普通成員變量的調(diào)用方式一致都采用.的操作符。

下面給出一個完整的例子:

#include<iostream.h>

c1asstest

(

private:〃私有成員類外不可以直接訪問

§intnumber;

。publie:〃共有成員類外可以直接訪問

floatsocre;

叩ublic:

intrp()

returnnumber;

avoidsetnum(inta)

(

3number=a;

g}

};

voidmain()

(

?testa;

?//a.number=10;//錯誤的、私有成員不能外部訪問

a.socre=99.9f;

?cout<<a.socre?cndl;//公有成員可以外部訪問

a.setnum(100);//通過公有成員函數(shù)setnum()對私有成員number進行

賦值操作

cout?a.rp();〃間接返回私有成員number的值

cin.get();

)

運營結(jié)果:

99.9

100

2,在類體外定義成員函數(shù)

(1)內(nèi)聯(lián)函數(shù)和外聯(lián)函數(shù)。類的成員函數(shù)可以分為內(nèi)聯(lián)函數(shù)和外聯(lián)函數(shù)。內(nèi)聯(lián)函數(shù)是

指那些定義在類體內(nèi)的成員函數(shù),即該函數(shù)的函數(shù)體放在類體內(nèi),而說明在類體內(nèi),定義

在類體外的成員函數(shù)叫外聯(lián)函數(shù)。外聯(lián)函數(shù)的函數(shù)體定義在類的實現(xiàn)部分。

內(nèi)聯(lián)函數(shù)在調(diào)用時不是象一般函數(shù)那樣要轉(zhuǎn)去執(zhí)行被調(diào)用函數(shù)的函數(shù)體,執(zhí)行完畢后

再轉(zhuǎn)回調(diào)用函數(shù)中。而是在調(diào)用函數(shù)處用內(nèi)聯(lián)函數(shù)體的代碼來替換,這樣將會節(jié)省調(diào)用開

銷,提高運營速度。

內(nèi)聯(lián)函數(shù)與前面講過的帶參數(shù)的宏定義比較,它們的代碼效率是同樣的,但是內(nèi)聯(lián)函

數(shù)要優(yōu)于宏定義,由于內(nèi)聯(lián)函數(shù)遵循函數(shù)的類型和作用域規(guī)則,它與一般函數(shù)更相近,在

一些編譯器中,一旦關(guān)上內(nèi)聯(lián)擴展,將與一般函數(shù)同樣進行調(diào)用,調(diào)試比較方便。

在類體外定義的外聯(lián)函數(shù)可以用一種形式轉(zhuǎn)變成內(nèi)聯(lián)函數(shù),即在函數(shù)頭加上關(guān)鍵字

iniine就可以了。

⑵重載性。兩個以上的函數(shù),取同一個名字,只要使用不同類型的參數(shù)或參數(shù)個數(shù)

不同,編譯器便知道在什么情況下,調(diào)用哪個函數(shù)。這就叫做函數(shù)重載。

成員函數(shù)可以進行重載。構(gòu)造函數(shù)可以重載,而析構(gòu)函數(shù)不能重載。一般的成員函數(shù)

都可以重載。

上面介紹了在類內(nèi)部定義成員函數(shù)(方法)的方法,下面我們要介紹一下域區(qū)分符(::)

的作用。即在類外部定義成員函數(shù)。

下面我們來看一個例子,運用這個例子中我們要說明幾個重要問題:

nclude<iostream.h>

intpp=0;

classtest

private:

intnumber;

publie:

floatsocre;

intpp;

pub1ic:

voidrp();

);

VOidtest::rp()//在外部運用域區(qū)分符定義test類的成員函數(shù)

(

::PP=11;〃變量名前加域區(qū)分符給全局變量pp賦值

PP=100;〃設(shè)立結(jié)構(gòu)體變量

}

voidmain()

(

testa;

testb;

a.rp();

cout<<pp<<endl;

cout<<a.pp?endl;

cin.get();

)

運營結(jié)果:

11

100

問題一:

運用域區(qū)分符我們可以在類定義的外部設(shè)立成員函數(shù),但要注意的是,在類的內(nèi)部必

須預(yù)先聲明:

voidtest::rp()

在函數(shù)類型的后面加上類的名稱再加上域區(qū)分符(::)再加函數(shù)名稱,運用這樣的方

法我們就在類的外部建立了一個名為rp的test類大成員函數(shù)(方法),也許很多人要問,

這么做故意義嗎?在類的內(nèi)部寫函數(shù)代碼不是更好?

由于,在類的定義中,一般成員函數(shù)的規(guī)模一般都比較小,并且一些特殊的語句是不

可以使用的,并且一般會被自動的設(shè)立成為inline(內(nèi)聯(lián))函數(shù),即使你沒有明確的聲明

為:nline,那么為什么有會被自動設(shè)立成為inline呢?由于大多數(shù)情況下,類的定義一般

是放在頭文獻中的,在編譯的時候這些函數(shù)的定義也隨之進入頭文獻,這樣就會導(dǎo)致被多

次編譯,假如是inline的情況,函數(shù)定義在調(diào)用處擴展,就避免了反復(fù)編譯的問題,并且把

大量的成員函數(shù)都放在類中使用起來也十分不方便,為了避免這種情況的發(fā)生,所以C++

是允許在外部定義類的成員函數(shù)(方法)的,將類定義和其它成員函數(shù)定義分開,是面向

對象編程的通常做法,我們把類的定義在這里也就是頭文獻了看作是類的外部接口,類的

成員函數(shù)的定義當(dāng)作是類的內(nèi)部實現(xiàn)。寫程序的時候只需要外部接口也就是頭文獻即可,

這一特點和我們使用標(biāo)準(zhǔn)庫函數(shù)的道理是一致的,由于在類的定義中,已經(jīng)包含了成員函

數(shù)(方法)的聲明。

問題二:

域區(qū)分符和外部全局變量和類成員變量之間的關(guān)系。在上面的代碼中我們看到了,外

部全局和類內(nèi)部都有一個叫做PP的整形變量,那么我們要區(qū)分操作他們用什么方法呢?

使用域區(qū)分符就可以做到這一點,在上面的代碼中::PP-11;操作的就是外部的同名

稱全局變量,PP=100;操作的就是類內(nèi)部的成員變量,這一點十分重要!

問題三:

一個類的所有對象調(diào)用的都是同一段代碼,那么操作成員變量的時候計算機有是如何

知道哪個成員是屬于哪個對象的呢?

這里牽扯到一個隱藏的this指針的問題,上面的代碼在調(diào)用a.rp()的的時候,系

統(tǒng)自動傳遞一了個a對象的指針給函數(shù),在內(nèi)部的時候pp=100;的時候其實就是this

->PP=100;

所以你把上面的成員函數(shù)寫成如下形勢也是對的的:

voidtest::rp()

::pp=ll;

this->pp=100;//this指針就是指向a對象的指針

)

類的成員函數(shù)和普通函數(shù)同樣是可以進行重載操作的,關(guān)于重載函數(shù),我們將在后面

討論,這里只給出一個例子看看:

#inc1ude<iostream.h>

c1asstest

(

private:

intnumber;

public:

f1oatsocre;

intpp;

pub1ic:

voidrp(int);

voidrp(float);

);

voidtest::rp(inta)//'在外部運用域區(qū)分符定義test類的成員函數(shù)

(

cout<<”調(diào)用成員函數(shù)!a:^<<a<<end1;

}

voidtest::rp(floata)〃在外部運用域區(qū)分符定義test類的成員函數(shù)

(

coutV〈”調(diào)用成員函數(shù)!a:"<<a<<endl;

)

voidmain()

testa;

a.rp(100);

a.rp(3.14f);

cin.get();

)

運營結(jié)果:

調(diào)用成員函數(shù)!a:100

調(diào)用成員函數(shù)!a:3.14

3.運用指針和引用調(diào)用類的成員函數(shù)

下面我們來看一下運用指針和運用引用間接調(diào)用類的成員函數(shù),對于指針和引用調(diào)用

成員函數(shù)和調(diào)用普通函數(shù)差別不大,在這里也就不再反復(fù)說明了,注意看代碼,多試多練習(xí)

即可。

代碼如下:

#include<iostream.h>

classtest

(

private:

intnumber;

public:

floatsocre;

intpp;

public:

intrp(int);

);

inttest::rp(inta)//在外部運用域區(qū)分符定義test類的成員函數(shù)

number=100;

returna+number;

}

voidrun(test*p)//運用指針調(diào)用

(

cout?p->rp(100)<<endl;

)

voidrun(test&p)〃運用引用

(

cout<<p.rp(200)?endl;

}

voidmain()

(

testa;

run(&a);

run(a);

cin.get();

)

運營結(jié)果:

200

300

4.類成員的保護性

前面我們說過,類的成員假如不顯式的生命為public那么它默認(rèn)的就是private

就是私有的,私有聲明可以保護成員不可以被外部訪問,但在C++尚有一個修飾符,它具有

和private相似的性能,它就是protected修飾符。

在這里我們簡樸說明一下,他們?nèi)g的差別:

在類的private:節(jié)中聲明的成員(無論數(shù)據(jù)成員或是成員函數(shù))僅僅能被類的成員函

數(shù)和友元訪問。

在類的protected:節(jié)中聲明的成員(無論數(shù)據(jù)成員或是成員函數(shù))僅僅能被類的

成員函數(shù),友元以及子類的成員函數(shù)和友元訪問。

在類的public:節(jié)中聲明的成員(無論數(shù)據(jù)成員或是成員函數(shù))能被任何人訪問。

由于private和protected的差別重要是體現(xiàn)在類的繼承中,現(xiàn)在的教程還沒有設(shè)

計到友元和子類所以這里不做進一步討論,但上面的三點務(wù)必記得,在以后我們會回過頭

來說明的。

總的來說,類成員的保護無非是為了以下四點:

⑴相對與普通函數(shù)和其它類的成員函數(shù)來說,保護類的數(shù)據(jù)不可以被肆意的篡改侵

犯!

(2)使類對它自身的內(nèi)部數(shù)據(jù)維護負(fù)責(zé),只有類自己才可以訪問自己的保護數(shù)據(jù)!

⑶限制類的外部接口,把一個類提成公有的和受保護的兩部分,對于使用者來說它

只要會用就可以,無須了解內(nèi)部完整結(jié)構(gòu),起到黑盒的效果。

(4)減少類與其它代碼的關(guān)聯(lián)程,類的功能是獨立的,不需要依靠應(yīng)用程序的運營環(huán)

境,這個程序可以用它,此外一個也可以用它,使得你可以容易的用一個類替換另一個類。

下面為了演示類成員的保護特性,我們來做一個球類游戲!

我們設(shè)計一個類,來計算球員的平均成績,規(guī)定在外部不可以隨意篡改球員的平均成

績。

我們把該類命名為ballscore并且把它放到bal1score.h的有文獻中!

classballscore

叩rotected:

?>intgbs;〃好球單位得分

intbbs;//壞球單位扣分

?floatgradescore;//平均成績

?public:

voidinit()

gbs=5;

abbs=-3;

4}

。floatGetGS(f1oatgoodball,floatbadball)//goodba11好球數(shù),

badba11壞球數(shù)

(

。gradescore=(goodbal1*gbs+badba11*bbs)/(goodball+badb

all);

areturngradescore"/返回平均成績

)

);

主函數(shù)調(diào)用:

#include<iostream.h>

#include"ballscore.h〃

voidmain()

(

?ballscorejeff;

^cout?jeff.GetGS(10,3);

//jeff.gradescore=5.5;//想篡改jeff的平均成績是錯誤的!

jeff.init();

cin.get();

}

在上面的代碼中頭文獻和類的使用很好了體現(xiàn)了類的黑盒特性,誰也不可以在外部修

改球員的平均成績。

5.類的作用或

下面我們說一下關(guān)于類的作用域。在說內(nèi)容之前我們先給出這部分內(nèi)容的一個完整代

碼,看講解的是參照此一下代碼。

#include<iostream,h>

c1assba11score

(

oprotected:

ointgbs;〃好球單位得分

ointbbs;//壞球單位扣分

。floatgscore;〃平均成績

pub1ic:

svoidinit()

。(

??gbs-5;

obbs=-3;

a}

of1oatGetGS(floatgb,floatbb)

8intgscore=0;//'定義一個同名的類成員函數(shù)局部變量

?ballscore::gscore=(gb*gbs+bb*bbs)/(gb+bb);//由于

同名須加類名和域區(qū)分符

weturnballscore::gscore;//返回平均成績

a}

};

intballscorc=0;〃定義一個與類名稱相同的普通全局變量

inttest;

voidmain()

c1asstest〃局部類的創(chuàng)建

。{

gfloata;

8floatb;

);°

?testtest;

::test=l;〃由于局部類名隱藏了外部變量,使用時需加域區(qū)分符

oclassba11scorejeff;〃由于全局ballsocre和類名稱相同,需力口c1as

s前綴

jeff.init();

cout?jeff.GetGS(10,3);

)

類的作用域是只指定義和相應(yīng)的成員函數(shù)定義的范圍,在該范圍內(nèi),一個類的成員函

數(shù)對同一類的數(shù)據(jù)成員具有無限制的訪問權(quán)。

3.2.1構(gòu)造函數(shù)與析構(gòu)函數(shù)

構(gòu)造函數(shù)和析構(gòu)函數(shù)是類的兩個特殊的成員函數(shù)

1.構(gòu)造函數(shù)

構(gòu)造函數(shù)(constructor)是類的一個特殊的成員函數(shù),它與類名同名”當(dāng)定義該類的

對象時,構(gòu)造函數(shù)將被系統(tǒng)自動調(diào)用用以實現(xiàn)對該對象的初始化。

構(gòu)造函數(shù)不能有返回值,因而不能指定涉及void在內(nèi)的任何返回值類型。

構(gòu)造函數(shù)的定義與其他成員函數(shù)的定義同樣可以放在類內(nèi)或類外。

構(gòu)造函數(shù)的定義格式為:

類名(形參說明)

函數(shù)體

}

構(gòu)造函數(shù)既可以定義成有參函數(shù),也可以定義成無參函數(shù),要根據(jù)問題的需要來定。

注意:程序中不能直接調(diào)用構(gòu)造函數(shù),構(gòu)造函數(shù)是在創(chuàng)建對象時由系統(tǒng)直接調(diào)用的,

因比,在構(gòu)造函數(shù)中一般完畢初始化類成員變量的操作。

2.構(gòu)造函數(shù)的重載

一個類中出現(xiàn)了兩個以上的同名的成員函數(shù)時,稱為類的成員函數(shù)的重載。

在類的成員函數(shù)的重載中,比較常見形式是構(gòu)造函數(shù)的重載,當(dāng)類中出現(xiàn)了重載構(gòu)造

函數(shù)時,C++語言將根據(jù)構(gòu)造函數(shù)中的參數(shù)個數(shù)和類型選擇合適的構(gòu)造函數(shù)來完畢對象

的構(gòu)造。

3.默認(rèn)構(gòu)造函數(shù)與缺省參數(shù)的構(gòu)造函數(shù)

假如在類中沒有顯示定義構(gòu)造函數(shù),則編譯系統(tǒng)會為該類提供一個默認(rèn)的構(gòu)造函數(shù),

該默認(rèn)構(gòu)造函數(shù)是一個無參函數(shù),函數(shù)體為空,它僅僅負(fù)責(zé)創(chuàng)建對象,而不做任何初始化

工作(即不給相應(yīng)的數(shù)據(jù)成員賦初值),所以在該類的對象創(chuàng)建時不能保證有一個擬定的

初始狀態(tài)。

良好的編程習(xí)慣應(yīng)當(dāng)是給類提供合適的完畢初始化工作的構(gòu)造函數(shù)。但是,只要一個

類定義了一個構(gòu)造函數(shù)(不一定是無參構(gòu)造函數(shù)),編譯系統(tǒng)就不再提供默認(rèn)的構(gòu)造函數(shù)。

當(dāng)構(gòu)造函數(shù)具有缺省參數(shù)時,稱為具有缺省參數(shù)的構(gòu)造函數(shù),在使用品有缺省參數(shù)的構(gòu)造

函數(shù)時,要防止二義性。

4.拷貝構(gòu)造函數(shù)

拷貝構(gòu)造函數(shù)是一種特殊的構(gòu)造函數(shù)。定義拷貝構(gòu)造函數(shù)的一般格式為:

類名::類名(const類名&形式參數(shù))

函數(shù)體

拷貝構(gòu)造函數(shù)的函數(shù)名與類名同名。該函數(shù)也沒有返回值??截悩?gòu)造函數(shù)的功能是通

過將一個同類對象的值拷貝給一個新對象,來完畢對新對象的初始化,即用一個對象去構(gòu)

造比外一個對象。假如在類的定義中沒有定義拷貝構(gòu)造函數(shù),則編譯系統(tǒng)將自動生成一個

具有上述形式的默認(rèn)的拷貝構(gòu)造函數(shù),作為該類的公有成員。

5,析構(gòu)函數(shù)

與構(gòu)造函數(shù)相應(yīng)的是析構(gòu)函數(shù)。當(dāng)一個對象被定義時,系統(tǒng)會自動調(diào)用構(gòu)造函數(shù)為該

對象分派相應(yīng)的資源,當(dāng)對象使用完畢后且在對象消失前,系統(tǒng)會自動調(diào)用類的析構(gòu)函數(shù)

來釋放這些系統(tǒng)資源。

析構(gòu)函數(shù)也是類的一個特殊的成員函數(shù),其函數(shù)名稱是在類名的前面加上“?”;它

沒有返回值,也沒有參數(shù)。一個類中只能擁有一個析構(gòu)函數(shù),所以析構(gòu)函數(shù)不能重載。

析構(gòu)函數(shù)的定義方式為:

、類名()

函數(shù)體

假如程序員在定義類時沒有為類提供析構(gòu)函數(shù),則系統(tǒng)會自動創(chuàng)建一個默認(rèn)的析構(gòu)函

數(shù),其形式為:

~類名O{}

對象被析構(gòu)的順序與其創(chuàng)建時的順序正好相反,即最后構(gòu)造的對象最先被析構(gòu)。

假如一個對象是被new運算符動態(tài)創(chuàng)建的,當(dāng)使用de1ete運算符釋放它時,delet

e將會自動調(diào)用析構(gòu)函數(shù)。

示例:

//tdate1.h

c1assTDate1

private:

intyear,month,day;

叩ub1ic:

TDate1(inty,intm,intd);

o~TDate1();

voidPrint();

};

TDatel::TDate1(inty,intm,intd)

(

yearly;

omonth=m;

day=d;

ocout<<z,Constructorcalled.\n";

)

TDate1::Datc1()

(

cout?z,Destructorcalied.\n〃;

}

voidTDatel::Print()

(

cout?year<<z/.H<<month??z.*<<day?endl;

}

//tdatel.cpp

#include<iostream.h>

#inc1ude〃tdate1.h〃

intmain(void)

classTDateltoday(2023,3,9);

classTDateltomorrow(2023,3,10);

cout<<zztodayis〃;

today.Print();

。coutV<〃tomorrowis

tomorrow.Print();

<>return0;

)

運營結(jié)果:

Constructorcalled.

Constructorcalled.

todayis2023.3.9

tomorrowis2023.3.10

Dcstructorcalled.

Destructorcalled.

6.常對象與常對象成員

⑴常對象。常對象是指對象常量,其定義格式為:

const類名對象名;

從格式中可以看出,常對象的定義與一般對象的定義相比,在類名前必須加const關(guān)

鍵字。常對象具有以下特點:常對象在定義時必須進行初始化,并且在程序中不能再對其

進行更新;通過常對象只能調(diào)用類中的常成員函數(shù),而不能調(diào)用類中的其他成員函數(shù)。

⑵常對象成員。常對象成員分為常成員函數(shù)和常數(shù)據(jù)成員。

一是常成員函數(shù)。在類中,使用關(guān)鍵字const說明的成員函數(shù)成為常成員函數(shù),常

成員函數(shù)的說明格式為:

類型函數(shù)名(形參表)const;

類中的常成員函數(shù)與普通成員函數(shù)相比,具有以下特點:

常成員函數(shù)為類的只讀函數(shù),這種成員函數(shù)可以讀取數(shù)據(jù)成員的值,但不可以更新數(shù)

據(jù)成員的值,它也不能調(diào)用該類中沒有const修飾的其他成員函數(shù)。

常成員函數(shù)定義中的const關(guān)鍵字是函數(shù)類型的一部分,因此在其實現(xiàn)部分中也要

帶上const關(guān)鍵字。

常成員函數(shù)定義中的const關(guān)鍵字可以參與區(qū)分重載函數(shù)。

例如:

^include<iostream.h>

classTest_const

(

?private:

。intm;

pub1ic:

West_const(intargl)//構(gòu)造函數(shù)

。{

。m=arg1;

4

avoidsetv

溫馨提示

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

評論

0/150

提交評論