物件導向的三個基本特徵
物件導向的三個基本特徵是:封裝、繼承、多型。其中,封裝可以隱藏實現細節,使得**模組化;繼承可以擴充套件已存在的**模組(類);它們的目的都是為了——**重用。而多型則是為了實現另乙個目的——介面重用!
封裝
什麼是封裝?
封裝可以隱藏實現細節,使得**模組化;封裝是把過程和資料報圍起來,對資料的訪問只能通過已定義的介面。物件導向計算始於這個基本概念,即現實世界可以被描繪成一系列完全自治、封裝的物件,這些物件通過乙個受保護的介面訪問其他物件。在物件導向程式設計上可理解為:把客觀事物封裝成抽象的類,並且類可以把自己的資料和方法只讓可信的類或者物件操作,對不可信的進行資訊隱藏。
繼承
什麼是繼承?
繼承是指這樣一種能力:它可以使用現有類的所有功能,並在無需重新編寫原來的類的情況下對這些功能進行擴充套件。其繼承的過程,就是從一般到特殊的過程。
通過繼承建立的新類稱為「子類」或「派生類」。被繼承的類稱為「基類」、「父類」或「超類」。要實現繼承,可以通過「繼承」(inheritance)和「組合」(composition)來實現。在某些 oop 語言中,乙個子類可以繼承多個基類。但是一般情況下,乙個子類只能有乙個基類,要實現多重繼承,可以通過多級繼承來實現。
繼承的實現方式?
繼承概念的實現方式有三類:實現繼承、介面繼承和可視繼承。
1. 實現繼承是指使用基類的屬性和方法而無需額外編碼的能力;
2. 介面繼承是指僅使用屬性和方法的名稱、但是子類必須提供實現的能力;
3. 可視繼承是指子窗體(類)使用基窗體(類)的外觀和實現**的能力。
多型
什麼是多型?
多型性(polymorphisn)是允許你將父物件設定成為和乙個或更多的他的子物件相等的技術,賦值之後,父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作。簡單的說,就是一句話:允許將子類型別的指標賦值給父類型別的指標。
例子:(2012某軟體公司筆試題)**
請按順序寫出下面**的輸出結果:
答案:call child func
call ~child
call ~base
多型的實現方式分析?
實現多型,有二種方式,覆蓋,過載。覆蓋:是指子類重新定義父類的虛函式的做法。過載:是指允許存在多個同名函式,而這些函式的參數列不同(或許引數個數不同,或許引數型別不同,或許兩者都不同)。
分析:
「過載」是指在同乙個類中相同的返回型別和方法名,但是引數的個數和型別可以不同
「覆蓋\重寫」是在不同的類中。
其實,過載的概念並不屬於「物件導向程式設計」,過載的實現是:編譯器根據函式不同的參數列,對同名函式的名稱做修飾,然後這些同名函式就成了不同的函式(至少對於編譯器來說是這樣的)。如,有兩個同名函式:function func(p:integer):integer;和function func(p:string):integer;。那麼編譯器做過修飾後的函式名稱可能是這樣的:int_func、str_func。對於這兩個函式的呼叫,在編譯器間就已經確定了,是靜態的(記住:是靜態)。也就是說,它們的位址在編譯期就繫結了(早繫結),因此,過載和多型無關!真正和多型相關的是「覆蓋」。當子類重新定義了父類的虛函式後,父類指標根據賦給它的不同的子類指標,動態(記住:是動態!)的呼叫屬於子類的該函式,這樣的函式呼叫在編譯期間是無法確定的(呼叫的子類的虛函式的位址無法給出)。因此,這樣的函式位址是在執行期繫結的(晚邦定)。結論就是:過載只是一種語言特性,與多型無關,與物件導向也無關!引用一句bruce eckel的話:「不要犯傻,如果它不是晚邦定,它就不是多型。」
c++多型機制的實現:
該部分**:
1、c++實現多型的方法
物件導向有了乙個重要的概念就是物件的例項,物件的例項代表乙個具體的物件,故其肯定有乙個資料結構儲存這例項的資料,這一資料報括物件成員變數,如果物件有虛函式方法或存在虛繼承的話,則還有相應的虛函式或虛表指標,其他函式指標不包括。
虛函式在c++中的實現機制就是用虛表和虛指標,但是具體是怎樣的呢?從more effecive c++其中一篇文章裡面可以知道:是每個類用了乙個虛表,每個類的物件用了乙個虛指標。要講虛函式機制,必須講繼承,因為只有繼承才有虛函式的動態繫結功能,先講下c++繼承物件例項記憶體分配基礎知識:
從more effecive c++其中一篇文章裡面可以知道:是每個類用了乙個虛表,每個類的物件用了乙個虛指標。具體的用法如下:
class a
;class b : public a
; //a,b的實現省略
因為a有virtual void f(),和g(),所以編譯器為a類準備了乙個虛表vtablea,內容如下:
b因為繼承了a,所以編譯器也為b準備了乙個虛表vtableb,內容如下:
注意:因為b::g是重寫了的,所以b的虛表的g放的是b::g的入口位址,但是f是從上面的a繼承下來的,所以f的位址是a::f的入口位址。然後某處有語句 b bb;的時候,編譯器分配空間時,除了a的int a,b的成員int b;以外,還分配了乙個虛指標vptr,指向b的虛表vtableb,bb的布局如下:
當如下語句的時候:
a *pa = &bb;
pa的結構就是a的布局(就是說用pa只能訪問的到bb物件的前兩項,訪問不到第三項int b)
那麼pa->g()中,編譯器知道的是,g是乙個宣告為virtual的成員函式,而且其入口位址放在**(無論是vtalbea表還是vtalbeb表)的第2項,那麼編譯器編譯這條語句的時候就如是轉換:call *(pa->vptr)[1](c語言的陣列索引從0開始哈~)。
這一項放的是b::g()的入口位址,則就實現了多型。(注意bb的vptr指向的是b的虛表vtableb)
另外要注意的是,如上的實現並不是唯一的,c++標準只要求用這種機制實現多型,至於虛指標vptr到底放在乙個物件布局的**,標準沒有要求,每個編譯器自己決定。我以上的結果是根據g++ 4.3.4經過反彙編分析出來的。
2、兩種多型實現機制及其優缺點
c 封裝,繼承,多型
一 封裝 封裝是實現物件導向程式設計的第一步,封裝就是將資料或函式等集合在乙個個的單元中 我們稱之為類 被封裝的物件通常被稱為抽象資料型別。物件導向程式設計中一般以類作為資料封裝的基本單位。類將資料和運算元據的方法結合成乙個單位。在設計類時,不希望直接訪問類中的資料,而是希望通過方法來訪問資料。如此...
c 封裝,繼承,多型
c 中可使用類來達到資料封裝的效果,這樣可以使資料與方法封裝成單一元素,以便於通過方法訪問資料。除此之外,還可以控制資料的訪問方式。在物件導向程式設計中,大多數都是以類作為資料封裝的基本單位。類將資料和運算元據的方法結合成乙個單位。設計類時,不希望直接訪問類中的資料,而是希望通過方法來訪問資料。這樣...
C 封裝 繼承 多型
c 的封裝 封裝的是實現物件導向的第一步,封裝就是將資料 函式等集合在乙個單元也就是類中,封裝的目的是使得 模組化 封裝的意義在於增強安全性和簡化程式設計,使用者不必了解具體的實現細節,而只是通過外部介面以及特定的訪問許可權來使用類成員。c 定義了友元函式能夠訪問類中的私有函式 友元函式 eg 封裝...