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

下載本文檔

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

文檔簡(jiǎn)介

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

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

3.1.1歷史回顧

1967年挪威計(jì)算中心的KistenNygaard和OleJohanDahl開發(fā)了Simula67

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

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

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

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

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

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

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

問(wèn)世。1990年以來(lái),面向?qū)ο蠓治?、測(cè)試、度量和管理等研究都得到長(zhǎng)足發(fā)展。

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

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

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

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

了直接使用0T,而是運(yùn)用符號(hào)來(lái)表達(dá)機(jī)器指令,從而更方便地編寫程序;當(dāng)程序規(guī)模繼續(xù)

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

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

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

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

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

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

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

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

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

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

展和突破。

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

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

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

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

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

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

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

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

因此,SP的程序的基本特點(diǎn)是:

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

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

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

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

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

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

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

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

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

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

序設(shè)計(jì)者來(lái)說(shuō)只需了解它做什么(Whatt。do),而不必說(shuō)明:它如何去做(Howtod。)。

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

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

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

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

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

同的程序,可見(jiàn),使用傳統(tǒng)SP方法設(shè)計(jì)出來(lái)的程序或系統(tǒng),其可重用的成分很少.另一方

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

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

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

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

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

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

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

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

將其映射到對(duì)象的解空間就是:具體事物一一對(duì)象,抽象概念——類;而一個(gè)對(duì)象無(wú)非就是

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

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

目的:將世界上的問(wèn)題盡也許簡(jiǎn)樸化。

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

并處在不斷運(yùn)動(dòng)變化的事物(即對(duì)象)所組成。每個(gè)具體對(duì)象都可用兩個(gè)特性來(lái)把握:描

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

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

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

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

概言之,OOP與SP不同,它除了包納了sP的一切優(yōu)特點(diǎn)與機(jī)制外,同時(shí)又是一個(gè)引

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

大新方法。

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

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

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

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

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

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

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

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

d.消息-一對(duì)象之間通訊的途徑。

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

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

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

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

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

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

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

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

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

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

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

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

用性的軟件成份和機(jī)制。

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

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

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

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

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

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

一個(gè)語(yǔ)言要稱為面向?qū)ο笳Z(yǔ)言必須支持幾個(gè)重要面向?qū)ο蟮母拍?。根?jù)支持限度的不

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

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

承、多態(tài)。舉例來(lái)說(shuō),Ada就是一個(gè)典型的基于對(duì)象的語(yǔ)言,由于它不支持繼承、多態(tài),此外

其他基于對(duì)象的語(yǔ)言尚有A1phard、CLU.Euclid、Modula。面向?qū)ο蟮恼Z(yǔ)言中一部

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

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

些則是對(duì)現(xiàn)有的語(yǔ)言進(jìn)行改造,增長(zhǎng)面向?qū)ο蟮奶匦匝莼鴣?lái)的。如由Pasca1發(fā)展而來(lái)

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

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

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

位。

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

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

a.對(duì)象(0bject)

b.消息(Message)

c.方法(Method)

d.類(C1ass)

e.繼承(Inheritenee)

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

1.對(duì)象

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

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

與功能的程序。

從傳統(tǒng)的SP觀點(diǎn)來(lái)看,數(shù)據(jù)和解決它們的代碼是兩個(gè)不同的獨(dú)立實(shí)體,它們之間的

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

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

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

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

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

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

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

表中對(duì)消息操作名進(jìn)行按名搜索而已,相應(yīng)C++來(lái)說(shuō),執(zhí)行一個(gè)消息表達(dá)式就是觸發(fā)選擇機(jī)

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

代碼中運(yùn)營(yíng)。

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

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

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

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

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

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

象中的數(shù)據(jù)只可以由對(duì)象中的代碼塊(成員函數(shù))來(lái)訪問(wèn),即數(shù)據(jù)是對(duì)象私有的(受保護(hù)的),

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

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

知道如何去做的。

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

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

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

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

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

a.模塊獨(dú)立性。邏輯上看,一個(gè)對(duì)象是獨(dú)立存在的模塊,從外部看這模塊,只需了解它

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

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

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

波及或破壞別的模塊。

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

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

活機(jī)制,把對(duì)象之間動(dòng)態(tài)聯(lián)系連接起來(lái),便稱為對(duì)象的動(dòng)態(tài)連接性。

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

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

了對(duì)象和整個(gè)系統(tǒng)的易維護(hù)性。

2.消息

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

通俗地講QOP中的術(shù)語(yǔ)“消息”只但是是現(xiàn)實(shí)世界中的“請(qǐng)求”、“命令”等平常生

活用語(yǔ)的同義詞。

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

個(gè)實(shí)參)和接受消息的對(duì)象三個(gè)部分組成。

從程序設(shè)計(jì)語(yǔ)言的角度出發(fā)來(lái)說(shuō),除前面曾經(jīng)提到過(guò)的消息具有提供(激活)對(duì)象的動(dòng)

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

如代碼:

switch(message)

(

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

break;

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

break;

)

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

系,只能通過(guò)傳送消息即執(zhí)行消息表達(dá)式來(lái)進(jìn)行。對(duì)象也只有在收到消息時(shí),才被激活,

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

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

3.方法

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

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

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

實(shí)現(xiàn)而已。

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

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

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

4.類

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

和相同操作成員的對(duì)象的定義和說(shuō)明。而每個(gè)對(duì)象都是某個(gè)類的一個(gè)具體實(shí)例。

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

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

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

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

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

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

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

及操作特性和存儲(chǔ)特性都集中封裝起來(lái)。由屬于此類的對(duì)象共享。例如,討論食肉動(dòng)物時(shí),

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

又如:若為屏幕上的點(diǎn)設(shè)計(jì)一個(gè)類如下:

classpoint

(

x,y;

new();

deleteO;

move();

highlight();

}

則可以說(shuō)明point類的對(duì)象如:

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

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

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

5.繼承

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

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

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

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

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

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

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

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

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

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

繼承機(jī)制有以下幾個(gè)優(yōu)特點(diǎn):

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

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

c.能通過(guò)增強(qiáng)一致性來(lái)減少模塊間的接口和界面,增強(qiáng)程序的易維護(hù)性。

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

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

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

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

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

繼承,每個(gè)子類只能有一個(gè)父類,而對(duì)多重繼承,每個(gè)子類則可以有多個(gè)父類。

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

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

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

此泛指例程、函數(shù)、過(guò)程)用于完畢這些任務(wù),解決問(wèn)題的焦點(diǎn)集中于函數(shù)。其中函數(shù)是

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

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

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

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

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

證。面向?qū)ο蟪绦蛟O(shè)計(jì)的出發(fā)點(diǎn)之一就是填補(bǔ)面向過(guò)程程序設(shè)計(jì)中的一些缺陷:對(duì)象是程

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

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

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

點(diǎn):

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

避免對(duì)外界的干擾;

⑵通過(guò)繼承大幅減少冗余的代碼,并可以方便地?cái)U(kuò)展現(xiàn)有代碼,提高編碼效率,也減

低了犯錯(cuò)概率,減少軟件維護(hù)的難度;

⑶結(jié)合面向?qū)ο蠓治?、面向?qū)ο笤O(shè)計(jì),允許將問(wèn)題域中的對(duì)象直接映射到程序中,減

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

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

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

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

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

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

外在功能上的擴(kuò)充,從而實(shí)現(xiàn)對(duì)象由低到高的升級(jí)。

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

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

1.繼承性

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

2.封裝性

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

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

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

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

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

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

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

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

總之,我們可以這樣來(lái)定義封裝:

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

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

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

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

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

這就是OOP中對(duì)象的封裝性。

3.多態(tài)性

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

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

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

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

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

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

Iabs()返回long的絕對(duì)值

fabs()返回double的絕對(duì)值

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

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

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

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

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

#include<iostream.h>

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

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

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

mainO

(

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

cout?abs(-11.0)?u\nw;

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

}

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

變量類型自動(dòng)錄找對(duì)的的那個(gè)函數(shù)進(jìn)行運(yùn)算,這就將要記住的三件事減少為只須記住一件

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

的多態(tài)性。

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

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

形式與系統(tǒng)完畢連接稱為靜態(tài)連接,而在運(yùn)營(yíng)時(shí)進(jìn)行上述連接的則稱為動(dòng)態(tài)連接。

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

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

方便性大大增強(qiáng)。

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

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

個(gè)對(duì)象的某個(gè)功能時(shí),它把請(qǐng)求以消息的形式傳送給接受者就算了事,至于接受對(duì)象如何

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

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

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

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

3.1.7面向?qū)ο笤O(shè)計(jì)方法的特點(diǎn)和面臨的問(wèn)題

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

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

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

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

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

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

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

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

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

3.2類和對(duì)象

3.2.1類和對(duì)象概述

1.類和對(duì)象的聲明

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

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

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

我們?cè)贑語(yǔ)言中創(chuàng)建一個(gè)結(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++中的類可以,

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

過(guò)去的C語(yǔ)言是一種非面向?qū)ο蟮恼Z(yǔ)言,它的特性是:程序=算法+數(shù)據(jù)結(jié)構(gòu)。但C++

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

特性,我們?cè)诙x一個(gè)自己定義的結(jié)構(gòu)體變量的時(shí)候。這個(gè)變量就應(yīng)當(dāng)是叫做對(duì)象或者叫

實(shí)例。

例如:

testa;

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

如:

a.socre=10.1f;

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

e;

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

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

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

大。

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

testa;

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

a.rp();

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

下面給出一個(gè)完整的例子:

#include<iostream.h>

c1asstest

(

private:〃私有成員類外不可以直接訪問(wèn)

。intnumber;

opublic:〃共有成員類外可以直接訪問(wèn)

floatsocre;

opublic:

intrp()

returnnumber;

°}

svoidsetnum(inta)

(

。number=a;

};

voidmain()

(

◎testa;

Mla.number=10;//錯(cuò)誤的,私有成員不能外部訪問(wèn)

a.socre=99.9f;

ocout<<a.socre?endl;//公有成員可以外部訪問(wèn)

a.setnum(100);//通過(guò)公有成員函數(shù)setnum()對(duì)私有成員number進(jìn)行

賦值操作

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

cin.get();

)

運(yùn)營(yíng)結(jié)果:

99.9

100

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

⑴內(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)。而說(shuō)明在類體內(nèi),定義

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

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

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

銷,提高運(yùn)營(yíng)速度。

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

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

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

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

iniine就可以了。

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

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

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

都可以重載。

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

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

下面我們來(lái)看一個(gè)例子,運(yùn)用這個(gè)例子中我們要說(shuō)明幾個(gè)重要問(wèn)題:

#include<iostream.h>

intpp=0;

classtest

private:

intnumber;

publie:

floatsocre;

intpp;

pub1ic:

voidrp();

);

voidtest::rp()//在外部運(yùn)用域區(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();

)

運(yùn)營(yíng)結(jié)果:

11

100

問(wèn)題一:

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

須預(yù)先聲明:

voidtest::rp()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

問(wèn)題二:

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

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

使用域區(qū)分符就可以做到這一點(diǎn),在上面的代碼中::pp=l1;操作的就是外部的同名

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

問(wèn)題三:

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

知道哪個(gè)成員是屬于哪個(gè)對(duì)象的呢?

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

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

->pp=100;

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

voidtest::rp()

::pp=ll;

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

}

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

討論,這里只給出一個(gè)例子看看:

#inc1ude<iostream.h>

c1asstest

(

private:

intnumber;

public:

f1oatsocre;

intpp;

pub1ic:

voidrp(int);

voidrp(float);

);

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

{

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

)

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

{

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

)

voidmain()

testa;

a.rp(100);

a.rp(3.14f);

cin.get();

)

運(yùn)營(yíng)結(jié)果:

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

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

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

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

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

即可。

代碼如下:

#include<iostream.h>

classtest

(

private:

intnumber;

public:

floatsocre;

intpp;

public:

intrp(int);

};

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

number=100;

returna+number;

)

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

{

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

)

voidrun(test&p)〃運(yùn)用引用

(

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

)

voidmain()

(

testa;

run(&a);

run(a);

cin.get();

)

運(yùn)營(yíng)結(jié)果:

200

300

4.類成員的保護(hù)性

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

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

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

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

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

數(shù)和友元訪問(wèn)。

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

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

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

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

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

來(lái)說(shuō)明的。

總的來(lái)說(shuō),類成員的保護(hù)無(wú)非是為了以下四點(diǎn):

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

犯!

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

⑶限制類的外部接口,把一個(gè)類提成公有的和受保護(hù)的兩部分,對(duì)于使用者來(lái)說(shuō)它

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

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

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

下面為了演示類成員的保護(hù)特性,我們來(lái)做一個(gè)球類游戲!

我們?cè)O(shè)計(jì)一個(gè)類,來(lái)計(jì)算球員的平均成績(jī),規(guī)定在外部不可以隨意篡改球員的平均成

績(jī)。

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

classballscore

?protected:

?intgbs;〃好球單位得分

intbbs;//壞球單位扣分

efloatgradescore;//平均成績(jī)

?public:

voidinit()

gbs=5;

gbbs=-3;

°)

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

badba11壞球數(shù)

(

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

all);

greturngradescore;〃返回平均成績(jī)

}

);

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

#include<iostream.h>

#include"ballscore.h〃

voidmain()

(

?ballscorejeff;

ocout?jeff.GetGS(10,3);

//jeff.gradescore=5.5;//想篡改jeff的平均成績(jī)是錯(cuò)誤的!

jeff.init();

cin.get();

)

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

改球員的平均成績(jī)。

5.類的作用域

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

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

#include<iostream,h>

c1assba11score

(

oprotected:

aintgbs;〃好球單位得分

ointbbs;//壞球單位扣分

。floatgscore;〃平均成績(jī)

pub1ic:

。voidinit()

%I

°ogbs=5;

obbs=-3;

g}

of1oatGetGS(floatgb,floatbb)

g{

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

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

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

?returnballscore::gscore;//返回平均成績(jī)

g}

);

intballscore=0;〃定義一個(gè)與類名稱相同的普通全局變量

inttest;

voidmain()

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

?(

afloata;

8floatb;

};°

?testtest;

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

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

s前綴

jeff.init();

cout<<jeff.GetGS(10,3);

)

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

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

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

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

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

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

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

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

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

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

類名(形參說(shuō)明)

函數(shù)體

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

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

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

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

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

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

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

的構(gòu)造。

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

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

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

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

初始狀態(tài)。

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

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

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

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

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

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

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

函數(shù)體

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

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

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

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

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

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

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

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

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

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

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

'類名()

(

函數(shù)體

)

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

數(shù),其形式為:

~類名(){)

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

假如一個(gè)對(duì)象是被new運(yùn)算符動(dòng)態(tài)創(chuàng)建的,當(dāng)使用de1ete運(yùn)算符釋放它時(shí),delet

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

示例:

//tdate1.h

c1assTDate1

(

private:

intyear,month,day;

叩ub1ic:

TDate1(inty,intm,intd);

「TDate1();

voidPrint();

);

TDatel::TDate1(inty,intm,intd)

(

year=y;

叩ionth=m;

day=d;

6cout<<,/Constructorcalled.\nu;

)

TDate1::^TDatel()

{

cout?,zDestructorcalied.\n〃;

)

voidTDatel::Print()

(

cout<<year<<,z,"?month<<//.z,?day?endl;

)

//tdatel.cpp

#include<iostream.h>

#inc1ude〃tdate1.h〃

intmain(void)

classTDateltoday(2023,3,9);

classTDateltomorrow(2023,3,10);

coutV<"todayis〃;

today.Print();

ocout<</ztomorrowis〃;

tomorrow.Print();

oreturn0;

}

運(yùn)營(yíng)結(jié)果:

Constructorcalled.

Constructorcalled.

todayis2023.3.9

tomorrowis2023.3.10

Destructorcalied.

Destructorcalled.

6.常對(duì)象與常對(duì)象成員

(1)常對(duì)象。常對(duì)象是指對(duì)象常量,其定義格式為:

const類名對(duì)象名;

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

鍵字。常對(duì)象具有以下特點(diǎn):常對(duì)象在定義時(shí)必須進(jìn)行初始化,并且在程序中不能再對(duì)其

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

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

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

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

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

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

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

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

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

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

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

例如:

#include<iostream.h>

classTest_const

(

oprivate:

。intm;

pub1ic:

<>Test_const(intargl)//構(gòu)造函數(shù)

。m=arg1;

。}

woidsetvalue(intnewvalue);

woidshowvalue();

ovoidshowvalue()const;//常成員函數(shù)

);

voidTestconst::setvalue(intnewvalue)

(

m=newvalue;

)

voidTestconst::showva1ue()

ocout<<//m=,z?m<<end1;

voidTest_const::showvalue()const//此處的const關(guān)鍵字不可少

(

?cout<〈"constexamplem="<Vm<<endl;

}

voidmain()

(

?Test_constc1(100);//定義對(duì)象c1

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 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ì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論