版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025湖南省建筑安全員《C證》考試題庫及答案
- 2025甘肅省建筑安全員-C證(專職安全員)考試題庫
- 2025年山西省建筑安全員A證考試題庫及答案
- XX科技集團開工大吉課件模板
- 班主任工作經(jīng)驗交流52
- 《心理健康案例》課件
- 《撲動及纖顫》課件
- 三年級科學(xué)復(fù)習(xí)
- 單位人力資源管理制度范文大全十篇
- 單位管理制度展示大全人員管理篇
- 手術(shù)室安全核查制度及流程課件
- 2024-2025學(xué)年高中英語選擇性必修 第二冊北師大版(2019)教學(xué)設(shè)計合集
- 高標(biāo)準(zhǔn)農(nóng)田跟蹤審計、工程中間計量、變更價格調(diào)整及竣工結(jié)算審核項目 投標(biāo)方案(技術(shù)方案)
- 感恩節(jié)英文課件
- 慈溪市2024-2025學(xué)年四上數(shù)學(xué)期末教學(xué)質(zhì)量檢測模擬試題含解析
- 人教版小學(xué)一年級語文上冊全冊試卷全套含答案
- 2025年高考化學(xué)二、三輪復(fù)習(xí)策略講座
- 2024-2025學(xué)年哈爾濱市平房區(qū)四上數(shù)學(xué)期末調(diào)研試題含解析
- 2022年高考數(shù)學(xué)試卷(上海)(秋考)(空白卷)
- 山東省濟南市語文小升初2024年模擬試題與參考答案
- 裝配式建筑復(fù)習(xí)試題及答案
評論
0/150
提交評論