說起面向對象,大家可能會想到其他的,但是此對象非彼對象哈哈,不必驚慌,也特別好搞定。
在聽到面向對象之前大家也一定會接觸學習到面向過程相關的,那么它們兩個之間到底是有什么關系呢,我先給咱嘮嘮。
面向過程與面向對象的區別
面向過程—步驟化
當軟件規模超過一定的尺度后,采用結構化程序設計,其開發和維護就越來越難控制。其根本原因就在于面向過程的結構化程序設計的方法與現實世界往往都不一致,結構化程序設計的思想往往很難貫徹到底。
在結構化程序設計中,采用的是“ 自頂向下,逐步細化 ”的思想。具體操作方法是模塊化,是按功能來分的,所以也稱功能塊。在C++中稱為一個函數,一個函數解決一個問題,即實現一個功能或一個操作。
在模塊化的思想中已經出現了封裝的概念,這個封裝是把數據封裝到模塊中,即局部變量。但這是很不徹底的,因為模塊是功能的抽象,而數據則是具有其個性的,一旦發生哪怕是一點變化,抽象的功能模塊就不再適用了。可維護性差成了制約機構化程序設計應用的瓶頸。
總的來說,面向過程就是分析出實現需求所需要的步驟,通過函數一步一步實現這些步驟,接著依次調用即可。
面向對象—行為化
面向對象是把整個需求按照特點、功能劃分,將這些存在共性的部分封裝成類(類實例化后才是對象),創建了對象不是為了完成某一個步驟,而是描述某個事務在解決問題的步驟中的行為。
對象是面向對象技術的核心所在,面向對象技術中的對象就是現實世界中某個具體的物理實體在計算機邏輯中的映射和體現。
面向過程和面向對象的優缺點及用途
總結:
- 類是一組相關的 屬性(變量) 和 行為(方法) 的集合。是一個抽象概念設計的產物。
- 對象是該類事物的具體表現形式。具體存在的實體。
- 成員變量是對象的屬性(可以使變量、指針、數組等),屬性的值確定對象的狀態。
- 成員函數是對象的方法,確定對象的行為。
狀態和行為是對象的主要屬性
對象的狀態又稱為對象的靜態屬性,主要指對象內部所包含的各種信息,也就是變量。每個對象個體都有自己專有的內部變量,這些變量的值標明了對象所處的狀態。
對象的方法(行為)一方面把對象的內部變量包裹,封裝,保護起來,使得只有對象自己的方法才能操作這些內部變量,另一方面,對象的方法還是對象與外部環境和其他對象交互,通信的接口,對象的環境和其他對象可以通過這個接口來調用對象的方法,操縱對象的行為和改變對象的狀態。
對象是現實世界的實體或概念在計算機邏輯中的抽象表示。具體地,對象是具有唯一對象名和固定對外界接口的一組屬性和操作的集合,用來模擬或影響現實世界問題的一個或一組因素。
相對于傳統的面向過程的程序設計方法,而面向對象的程序設計具有的優點
對象的數據封裝特性徹底消除了傳統結構方法中數據與操作分離所帶來的種種問題,提高了程序的可復性和可維護性,降低了程序員保持數據與操作相容的負擔。
對象的數據封裝特性還可以把對象的私有數據和公共數據分離開,保護了私有數據,減少了可能的模塊間干擾,達到降低程序復雜性,提高可控性的目的。
對象作為獨立的整體具有良好的自恰性,即它可以通過自身定義的操作來管理自己。一個對象的操作可以完成兩類功能,一是修改自身的狀態,二是向外界發布消息。
在具有自恰性的同時,對象通過一定的接口和相應的消息機制與外界聯系。這個特性與對象的封裝性結合在一起,較好地實現了信息的隱藏。
通過繼承可以很方便地實現應用的擴展和已有代碼的重復使用。
總結:
面向對象程序設計是將數據及數據的操作封裝在一起,成為一個不可分割的整體,同時將具有相同特性的實體抽象成為一種新的數據類型—類。通過對象間的消息傳遞是整個系統運轉。
類和對象關系和理解
類:一組相關的屬性和行為的集合,是一個抽象的概念。
對象:該類事務的具體表現形式,具體存在的個體。
上面這幾個概念,應該怎么理解的呢?
類就是對一些具有共性特征,并且行為相似的個體的描述。
比如小楊和小秦都有姓名、年齡、身高、體重等一些屬性,并且兩人都能夠進行聊天、運動等相似的行為。
由于這兩個人具有這些共性的地方,所以我們就把它抽象出來,定義為一個類—人類,而小楊、小秦正是這個類中的個體,而每一個個體才是真正的具體的存在,光提到人類,你只知道應該有哪些屬性行為,但你不知道他具體的一些屬性值。比如你知道他屬于“人類”,所以他應該擁有姓名,年齡等屬性,但你并不知道他具體叫什么,年齡多大了。而小楊和小秦這兩個具體的對象,卻能夠實實在在的知道小楊今年23歲了,體重80kg等值。
總結:
類是對象的抽象,而對象是類的具體實例。類是抽象的,不占用內存,而根據類實例化具體的對象,就需要占用內存空間了。
面向對象的三大主要特征
封裝
常見的兩層含義 :一是把對象的屬性和行為看成一個密不可分的整體,將這兩者“封裝”在一個不可分割的獨立單元中;另一個是指“ 信息隱藏 ”,把不需要讓外界知道的信息隱藏起來,有些對象的屬性及行為允許外界用戶知道或使用,但不允許更改,而另一些屬性或行為,則不允許外界知曉,或只允許使用對象的功能,而盡可能隱藏對象的功能實現細節。
封裝的好處:
- 可以對成員變量進行更精確的控制。
- 類內部的結構可以自由修改。
- 好的封裝能夠減少耦合,符合程序設計“高內聚,低耦合”。
- 隱藏實現細節。
- 提供公共的訪問方式。
- 提高代碼的復用性。
- 提高安全性。
繼承
繼承時面向對象編程技術的一塊基石,因為它允許創建分等級層次的類。
繼承就是在一個已有類的基礎上派生出新類(例如動物類可以派生出狗類和貓類),子類繼承父類的特征和行為,使得子類對象(實例)具有父類的實例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。
繼承的好處:
- 提高代碼的維護性。
- 提高類代碼的復用性。
- 使得類和類產生了關系,是多態的前提(是繼承的一個弊端,讓類的耦合性增強了)。
**繼承概念的實現方式有三類:實現繼承、接口繼承、可視繼承
**
實現繼承:使用基類的屬性和方法而無序額外編碼的能力。
接口繼承:僅使用屬性和方法的名稱,但是子類必須提供實現的能力。
可視繼承:子窗體使用基窗體的外觀和實現代碼的能力。
繼承的特點:
- 子類擁有父類非private的屬性,方法。
- 子類可以擁有自己的屬性和方法,即子類可以對父類進行擴展。
- 子類可以用自己的方式實現父類的方法,即重寫父類方法。
- 提高了類之間的耦合性。
訪問權限修飾符public、 protected 、private:
多態
多態是同一個行為具有多個不同表現形式或形態的能力,例如:黑白打印機和彩色打印機相同的打印行為卻有著不同的打印效果。
- 對象類型和引用類型之間存在著繼承(類)/ 實現(接口)的關系。
- 當使用多態方式調用方法時,首先檢查父類中是否有該方法,如果沒有,則編譯錯誤;如果有,再去調用子類的同名方法。
- 如果子類重寫了父類的方法,最終執行的是子類覆蓋的方法,如果沒有則執行的是父類的方法。
多態的實現: 靜態多態和動態多態
靜態多態:通過函數重載和模板來實現,是在編譯期間確定,也稱早起綁定。
動態多態:通過虛函數和繼承來實現,是在運行期確定,也稱晚期綁定(動態綁定)。
動態多態的實現:
當編譯器發現類中有虛函數時,會創建一張虛函數表,把虛函數的函數入口地址放到虛函數表中,并且在對象中增加一個指針vptr,用于指向類的虛函數表。當派生類覆蓋基類的虛函數時,會將虛函數表中對應的指針進行替換,從而調用派生類中覆蓋后的虛函數,從而實現動態綁定。
虛表:虛表中放置的是虛函數的入口地址,如果能拿到虛表中的內容,即拿到了虛函數的入口地址,則可以將該函數調用起來。
基類虛表構建過程 :編譯期間在編譯期間,按照虛函數在類中聲明的先后次序依次添加到虛表中。
派生類虛表的構建過程 :
- 將基類虛表中內容拷貝一份放置到子類虛表中。
- 如果子類重寫了基類的某個虛函數,則使用子類自己的虛函數替換相同偏移量位置的基類虛函數地址。
- 對于子類新增的虛函數,按照在類中聲明次序,依次放在虛表的后面。
函數重載、重寫、同名隱藏的對比:
函數重載:兩個或多個函數在同一作用域,函數名相同、參數列表不同。
重寫:兩個函數分別在基類和派生類的作用域中,函數名、參數、返回值類型都必須相同,基類虛函數必須為虛函數,派生類函數最好也為虛函數。
同名隱藏:兩個函數分別在基類和派生類的作用域中,函數名相同,基類和派生類同名函數不是重寫就是同名隱藏。
多態的優點:
消除類型之間的耦合關系、可替換性、可擴充性、接口性、靈活性、簡化性。
動態多態的作用:
- 隱藏實現細節,使代碼模塊化,提高代碼的可復用性。
- 接口重用,使派生類的功能可以被基類的指針/引用所調用,即向后兼容,提高代碼的可擴充性和可維護性。
動態多態的必****要條件:繼承、虛函數覆蓋、基類指針/引用指向子類對象。
總之,C++多態的核心,就是用一個更通用的基類指針指向不同的子類實例,為了能調用正確的方法,我們需要用到虛函數和虛繼承。在內存中,通過虛函數表來實現子類方法的正確調用;通過虛基類指針,僅保留一份基類的內存結構,避免沖突。
面向對象的五大原則
** 單一職責原則SRP** (Single Responsibility Principle):是指 一個類的功能要單一,不能包羅萬象 。如同一個人一樣,分配的工作不能太多,否則一天到晚雖然忙忙碌碌的,但效率卻高不起來。
**開放封閉原則OCP** (Open-Close Principle):一 個模塊在擴展性方面應該是開放的而在更改性方面應該是封閉的 。比如:一個網絡模塊,原來只服務端功能,而現在要加入客戶端功能,那么應當在不用修改服務端功能代碼的前提下,就能夠增加客戶端功能的實現代碼,這要求在設計之初,就應當將服務端和客戶端分開,公共部分抽象出來。
** 里式替換原則LSP** (the Liskov Substitution Principle LSP): 子類應當可以替換父類并出現在父類能夠出現的任何地方 。比如:公司搞年度晚會,所有員工可以參加抽獎,那么不管是老員工還是新員工,也不管是總部員工還是外派員工,都應當可以參加抽獎,否則這公司就不和諧了。
**依賴倒置原則DIP** (the Dependency Inversion Principle DIP): 高層模塊(穩定)不應該依賴低層模塊(變換)都應該依賴于抽象(穩定)。 抽象(穩定)不應該依賴于實現細節(變化),實現細節(變化)應該依賴于抽象(穩定) 。假設B是較A低的模塊,但B需要使用到A的功能,這個時候,B不應當直接使用A中的具體類:而應當由B定義一抽象接口,并由A來實現這個抽象接口,B只使用這個抽象接口:這樣就達到了依賴倒置的目的,B也解除了對A的依賴,反過來是A依賴于B定義的抽象接口。通過上層模塊難以避免依賴下層模塊,假如B也直接依賴A的實現,那么就可能 造成循環依賴。一個常見的問題就是編譯A模塊時需要直接包含到B模塊的cpp文件,而編譯B時同樣要直接包含到A的cpp文件。
**接口分離原則ISP** (the Interface Segregation Principle ISP): 模塊間要通過抽象接口隔離開 ,而不是通過具體的類強耦合起來。
-
編程
+關注
關注
88文章
3614瀏覽量
93686 -
面向對象
+關注
關注
0文章
64瀏覽量
9983 -
面向過程
+關注
關注
0文章
2瀏覽量
5816
發布評論請先 登錄
相關推薦
評論