C++面向對象:面向對象程序設計概述
會有點長,不過讀過就全學會嘍!!!!!!
會有點長,不過讀過就全學會嘍!!!!!!
會有點長,不過讀過就全學會嘍!!!!!!
1.什麼是面向對象程序設計
面向對象程序設計方法是通過增加軟件的可擴充性和可重 性來提高程序員的編程能力的 。
1.1 面向過程程序設計的基本概念
面向過程的程序設計思想的核心是功能的分解。數據結構和過程的這種分離, 給軟件人員 造成沉重的負擔。
1.2 面向對象程序設計的基本概念
在面向對象的程序設計 中,着重點在那些將要被操作的數據, 而不是在實現這些操作的過程。數據構成了軟件分 解的基礎,而不是功能。
不能將數據和相應操作看成兩個分離的實體, 而是要把它們作爲一個完 整的實體來對待。數據與定義在它上面的用戶需要的操作構成一個整體。同時, 數據本身不能被外部程序和過程直接存取。
面向對象程序設計的最大優點就是軟件具有可重用性。當人們對軟件系統的要求有 所改變時,並不需要程序員做大量的工作, 就能使系統做相應的變化。
類與對象是面向對象程序設計中最重要的概念
2.對象與類
2.1 對象與類的概念
在日常生活中對象就是我們認識世界的基本單元, 它可以是人,也可以是物, 還 可以是一件事。整個世界就是由形形色色的“對象”構成的。例如一輛車、一個球、一個小 學生、一次演出。對象既可以很簡單, 也可以很複雜, 複雜的對象可以由若干簡單的對象 構成。
對象是現實世界中的一個實體,其特性是:
- 每一個對象必須有一個名字以區別於其它對象;
- 用屬性( 或叫狀態)來描述它的某些特徵;
- 有一組操作,每一個操作決定對象的一種行爲。
在日常生活中“, 類”是對一組具有共同的屬性特徵和行爲特徵的對象的抽象。例如, 由一個個的人構成人類,而一個人是人類的一個實例。
類和對象之間的關係是抽象和具體的關係。類是對多個對象進行綜合抽象的結果, 對象又是類的個體實物,一個對象是類的一個實例。
以面向對象程序設計的觀點看, 一個對象是由描述其屬性的數 據和定義在其上面的一組操作組成的實體, 是數據單元和過程單元的組合體。類是對一 組對象的抽象,這組對象具有相同的屬性結構和操作行爲, 在對象所屬的類中要說明這些 結構和行爲。一個對象是類的一個實例。有了類,纔可以創建對象。
現在我們給出類的更精確的定義:類是創建對象的樣板, 它包含對創建對象的狀態描 述和對操作行爲的說明。
在面向對象程序設計中,一個類只在源程序的代碼中出現, 而並不會在一個正在內存 運行的程序中出現,即類只是在編譯時存在; 對象作爲類的實例在運行的程序中出現, 並 佔有內存空間,它是在運行時存在的實體。所以一個類實際上是一種新的數據類型, 當我 們要使用一個新的數據類型時,首先要在源程序中說明, 而說明部分的代碼是不在內存中 運行的。在程序中運行的是該類的對象,對象在內存中分配空間, 程序的計算任務由對象完成。注意,我們在此必須嚴格區分說明和定義。
2.2 對象的狀態
在面向對象程序設計中,對象是類的實例。對象給類以生命, 類想要做的事必須通過 建立對象和在對象上進行操作而實現。創建類的對象的過程也叫實例化對象。對象知道 什麼能做和什麼不能做,並且有能力修改和維護定義在對象上的數據。
我們可以將對象看成是一個帶有狀態和行爲的活的實體。
對象的狀態通常不僅僅是初等的數據類型 (整型、實型、字符型等 ) , 而且許多對象將 另一個對象作爲它們狀態的一部分。例如,一輛車有發動機、車輪、座位, 發動機是另外一 個對象, 它可以作爲車的狀態的一部分
在面向對象程序設計中,對象之間也需要聯繫, 我們稱爲對象的交互。面向對象程序設計技術必須提供一種機制,允許一個對象與另一個對象的交互。這種機制叫消息傳遞。
一般情況下,我們稱發送消息的對象爲發送者或請求者, 接收消息的對象爲接收者或 目標對象。對象中的聯繫只能通過消息傳遞來進行。接收者只有在接收到消息時, 才能 被激活,被激活的對象會根據消息的要求完成相應的功能。
消息具有三個性質:
- 同一個對象可以接收不同形式的多個消息, 做出不同的響應;
- 相同形式的消息可以傳遞給不同的對象,所做出的響應可以是不同的;
- 消息的發送可以不考慮具體的接受者, 對象可以響應消息,也可以不響應。
實際上, 對象之間的消息傳遞機制對應於面向過程程序設計的過程調用。消息傳遞並非真的傳遞信息,它的實質就是方法的調用。只不過方法的調用受到消息的控制, 而過程調用是直接的。
在面向對象程序設計中,消息分爲兩類: 公有消息和私有消息。假設有一批消息同屬 於一個對象,其中一部分消息是由其它對象直接向它發送的, 稱爲公有消息; 另一部分消 息是它向自己發送的,稱爲私有消息。
公有消息與私有消息的確定, 與消息要求調用的方法有關。如果被調用的方法在對象所屬的類中是在 public 下說明的, 則爲公有; 是在 private 下說明的 , 即爲私有。當然, 私有消息只能發送調用屬於它自己的方法
2.4 類的確定與劃分
類的確定與劃分是非常重要的, 是軟件開發中關鍵的一步, 劃分的結果直接影響到軟件系統的質量。如果劃分得當,既有利於對程序進行擴充, 又可提高代碼的可重用性。
值得注意的是,類的確定和劃分並沒有統一的標準和固定的方法, 基本 上依賴設計人員的經驗、技巧以及對實際問題的把握。一個基本的原則是: 尋求一個大系 統中事物的共性,將具有共性的系統成分確定爲一個類。
不能把一組函 數組合在一起構成類。也就是說, 不能把一個面向過程的模塊直接變成類。如果簡單地 將模塊中的函數變成成員函數而使其成爲類是錯誤的。類不是函數的集合
例如,考慮一個包含一組數學函數的模塊, 現在我們定義一個類 Mathhelper:
class Mathelper{
public:
double sqrt( double aNumber) ;
double Power( double aNumber, int raiseto ) ;
double Inverse ( double aNumber) ;
private :
// 任何數據項,也可能沒有
};
確定 Mathelper 爲一個類是錯誤的。問題在於該類中沒有需要管理的私有數據。用 戶只需要提供參數對成員函數進行調用。這與面向過程的程序設計的函數調用沒有根本的區別。
設計類要有一個明確的目標。一個好的類應該是容易理解和使用的。我們不能設計 一個 Color 類來表示鮮花的顏色,但是可以在圖形處理系統中將顏色 Color 設計爲類。因 爲在兩個系統中對顏色的要求不同。
3.數據的抽象與封裝
面向對象系統中最突出的特性是封裝性、繼承性和多態性。我們首先來討論封裝性。 封裝與數據抽象的概念密切相關。
3.1 現實世界中的抽象與封裝
以錄音機爲例,錄音機上有若干按鍵, 當人們使用錄音機時,只要根據自己的需要, 如 放音、錄音、停止、倒帶等, 按下與之對應的鍵, 錄音機就會完成相應的工作。這些按鍵安 裝在錄音機的表面,人們通過它們與錄音機交互。我們無法( 當然也沒必要) 操作錄音機 的內部電路,因爲它們被裝在機殼裏, 錄音機的內部情況對於用戶來說是隱蔽的, 不可見 的。這就是所謂封裝的原理。
以一般觀點而言,抽象是通過特定的實例或例子抽取共同性質以後形成概念的過程。 抽象是對系統的簡化描述或規範說明, 它強調了系統中的一部分細節和特性, 例如做什 麼,而忽略了其它部分, 例如如何做。抽象的描述被稱爲它的規範說明, 例如錄音機的操 作說明書,而對抽象的解釋稱爲它的實現。
3.2 數據的抽象與封裝的基本概念
將數據結構和作用於 數據結構上的操作組成一個實體,數據的表示方式和對數據的操作細節被隱藏起來, 用戶 通過操作接口對數據進行操作。對於用戶來說, 只知道如何通過操作接口對該數據進行操作,而並不知道是如何做的, 也不知道數據是如何表示的。這就是數據的封裝。
- 數據的抽象是在確定類時強調對象的共同點而忽略它們的 不同點的結果。也可以說,在一個類的說明中我們只表示那些主要特性, 而忽略次要的、 引不起我們興趣的東西。
- 數據的封裝則是隱藏了抽象的內部實現細節的結果。封裝是將數據抽象的外部接口 與內部的實現細節清楚地分離開。抽象和封裝是互補的。
好的抽象有利於封裝, 封裝的 實體則幫助維護抽象的完整性。重要的是抽象先於封裝
可以從下面幾點來理解對象的封裝:
- 對象具有一個清楚的邊 界, 對 象的私有數據、成員函數的 細節被封裝在該 邊 界內;
- 具有一個描述對象與其它對象如何相互作用的接口, 該接口必須說明消息傳遞 的使用方法;
- 對象內部的代碼和數據應受到保護,其它對象不能直接修改。
從用戶(或應用程序員) 的觀點看,對象提供了一組服務, 並提供了請求服務的接口。從系統設計員的角度看,封裝能夠清楚地標明對象提供的服務界面, 而對象的行爲和數據 是隱蔽的,看不見的。
3.3 對象的特性
(1 ) 封裝性
對象將私有元素和實現操作的內部細節隱藏起來, 並能管理自己的內部狀態。外部 只能從對象所表示的具體概念、對象提供的服務和對象提供的外部接口來認識對象。通 過向對象發送消息來激活對象的自身動作,達到施加特定操作的目的。
(2 ) 模塊獨立性
一個對象是一個獨立存在的模塊,具有獨立的計算能力; 並且其自身的變化不受外界 的干擾,也不會涉及到其它的模塊; 模塊間的依賴性極小或幾乎沒有; 各模塊可以獨立地 成爲軟件系統的組件,也可以被程序員重用。
(3 ) 動態連接性
對象的動態連接性是指對象通過消息傳遞機制將對象動態地聯繫在一起的特性。對 象能接收其它對象發送的消息,也能向其它對象發送消息。通過這種聯繫, 若干對象可協 同完成某項任務
(4 ) 易維護性
由於對象的功能被“隱蔽”,所以修改和完善的工作都被侷限於對象的內部, 不會涉及 到外部,因此使得對象和整個系統變得非常容易維護。
4.繼 承 性
4.1 繼承的概念
繼承在現實生活中是一個很容易理解的概念。例如, 我們每一個人都從我們的父母 身上繼承了一些特性,例如種族、血型、眼睛的顏色等, 我們身上的特性來自我們的父母, 也可以說,父母是我們所具有的屬性的基礎。
以面向對象程序設計的觀點來看, 繼承所表達的是對象類之間相關的關係。這種關 系使得某類對象可以繼承另外一類對象的特徵和能力。
若類之間具有繼承關係,則它們之間具有下列幾個特性:
- 類間具有共享特徵( 包括數據和程序代碼的共享) ;
- 類間具有差別或新增部分( 包括非共享的數據和程序代碼) ;
- 類間具有層次結構。
具體地說,繼承機制允許派生類繼承基類的數據和操作( 即數據成員和成員函數) , 也 就是說,允許派生類使用基類的數據和操作。同時, 派生類還可以增加新的操作和數據。 例如,子女類可以從父母類繼承房子和汽車, 當然可以使用房子和汽車, 還可以對房子進 行再裝修
面向對象程序設計爲什麼要提供繼承機制 ? 也就是說, 繼承的作用是什麼 ?
繼承的作用有兩個:
- 避免公用代碼的重複開發, 減少代碼和數據冗餘;
- 通過增強 一致性來減少模塊間的接口和界面
繼承機制爲程序員們提供了一種組織、構造和重用類的手段。
繼承機制以相關的關係來組織事物,可以減少我們對相似事物進行說明和記憶的規 模,爲我們提供了一種簡化的手段。
4.2 繼承的分類
繼承有兩種分類方法,一種是從繼承源上分, 另一種是從繼承內容上分。
從繼承源上分,繼承分爲單繼承和多繼承。
- 單繼承是指每個派生類只直接繼承了一個基類的特徵。
- 多繼承是指多個基類派生出一個派生類的繼承關係, 多繼承的派生類直接繼承了不止一個基類的特徵。
從繼承內容上劃分,繼承可分爲取代繼承、包含繼承、受限繼承、特化繼承。
- 取代繼承:例如徒弟從師傅那裏學到的所有技術, 在任何需要師傅的地方都可以由徒 弟來替代,這就屬於取代繼承。
- 包含繼承:例如“柯利狗”繼承了“狗”的所有特徵, 任何一條“柯利狗”都是一條“狗”, 這就屬於包含繼承。
- 受限繼承:例如“鴕鳥”儘管繼承了“鳥”的一些特徵, 但不能繼承鳥會飛的特徵, 這就 屬於受限繼承。
- 特化繼承: 例如“運動員”是一類特殊的人, 比一般人具有更多體育特長, 這就屬於特 化繼承。
4.3 繼承與封裝的關係
在面向對象程序設計中, 對象具有封裝性, 對象之間的聯繫只能通過消息傳遞來完 成,對象的私有數據和行爲是被隱藏起來的。
繼承與封裝不但沒有實質性的衝突, 而且還 有一定的相似性。
在面向對象系統中, 封裝的單位是對象, 也就是說, 把一個屬於某一類的對象封裝起 來,使其數據和操作成爲一個整體。如果該對象所屬的類是一個派生類, 那麼, 它只要把 從基類那裏繼承來的操作和數據與自己的操作和數據一併封裝起來, 就可以了。對象依 然是封裝好的整體,仍然只通過消息傳遞與其它的對象交互, 而不是直接調用。所以, 一 個對象,無論它是基類的實例, 還是派生類的實例,都是一個被封裝的實體。因此, 我們得 出結論:繼承機制的引入並不影響對象的封裝性。
從另一角度看, 繼承與封裝還有相似性, 那就是它們都提供了共享代碼的手段, 因而 增加了代碼的重用性。
繼承提供的代碼共享是靜態的,派生類對象在成爲活動的實體以後, 自動地共享其基 類中定義的代碼段,從而使基類對象與其派生類對象共享一段代碼。
封裝提供的代碼共享是動態的,例如我們在一個類中說明了一段代碼, 那麼屬於該類 的多個實例在程序運行時共享在類中說明的那段代碼。
5.多 態 性
5.1 什麼是多態性
多態性也是面向對象系統的重要特性。
現實世界的多態性在自然語言中經常出現。假設一輛 汽車停在了屬於別人的車位,司機可能會聽到這樣的要求“: 請把你的車挪開”,司機在聽 到請求後, 所做的工作應該是把車開走。在家裏, 一把凳子擋住了孩子的去路, 他可能會 請求媽媽“: 請把凳子挪開”, 媽媽過去搬起凳子,放在一邊。在這兩件事情中, 司機和媽媽 的工作都是“挪開”一樣東西,但是他們在聽到請求以後的行爲是截然不同的, 這就是多態性。對於“挪開”這個請求,還可以有更多的行爲與之對應。“挪開”從字面上看是相同的, 但由於用的對象不同,操作的方法就不同。
**面向對象程序設計借鑑了現實世界的多態性。面向對象系統的多態性是指不同的對 象收到相同的的消息時產生多種不同的行爲方式。**例如,我們有一個窗口 (Window)類對 象,還有一個棋子(ChessPiece )類對象, 現在我們來考慮對它們都發出“移動”的消息“, 移 動”操作在 Window 類對象和 ChessPiece 類對象上可以有不同的行爲。
C + + 語言支持兩種多態性, 即編譯時的多態性和運行時的多態性。
- 編譯時的多態 性是通過重載來實現的
- 運行時的多態性是通過虛函數來 實現的,程序運行的到底是哪個函數版本, 需要在運行時通過對象發送的消息來確定。
5.2 重載的概念
重載一般包括函數重載和運算符重載。函數重載是指一個標識符可同時用於爲多個 函數命名,而運算符重載是指一個運算符可同時用於多種運算。也就是說, 相同名字的函 數或運算符在不同的場合可以表現出不同的行爲。
下面我們給出一個函數重載的例子。
class A{
public:
void Print(int i) {語句段 1 ; }
void Print(float f) {語句段 2 ; }
void Print( const char * c) {語句段 3 ; }
// 其它語句
} ;
在上面的類定義中我們重載了三個函數, 名字都是 Print 。它們有各自不同的功能, 分別用語句段 1、語句段 2、語句段 3 中的語句實現, 在此略去語句的細節。函數名相同, 而函數實現的功能不同。那麼,當有要求使用 Print 函數的消息發送時, 到底應該執行函 數的哪一個呢 ? 這就要看消息傳遞的函數參數是什麼,根據參數來調用不同的同名函數。 例如,發送的消息是 Print( 20 ) , 則執行的是語句段 1,而發送的消息是 Print (”welcome”) , 則執行的是語句段 3。
爲什麼要使用重載 ?
使用重載的目的是爲了更好地表達行爲共享, 這種行爲共享就 像將相似的操作劃分在一起。使用重載可以使程序員在只知道操作的一般含義, 而不知 道操作具體細節的情況下能正確地對某個對象使用一個操作。
另外,使用重載的直接益處是減少了程序員記憶操作名字的負擔。
6.面向對象程序設計的語言
面向對象程序設計語 言應該具備下述特徵:
- 它支持對象的概念( 包括對象所有的特性,如封裝等) ;
- 它要求對象屬於類;
- 它提供繼承機制。
C + + 是對傳統 C 語言進行面向對象的擴充, 是在 C 語言的基礎上增加了對面向對 象程序設計的支持, 是在 80 年代早期由貝爾實驗室設計的。C + + 又被稱爲混合型語 言,因爲它可以支持傳統的程序設計方法, 又支持面向對象程序設計方法, 有豐富的應用 基礎和開發環境的支持,因而得到廣泛的使用。