C++中的封装、继承、多态
封裝(encapsulation):就是將抽象得到的數(shù)據(jù)和行為(或功能)相結(jié)合,形成一個有機的整體,也就是將數(shù)據(jù)與操作數(shù)據(jù)的源代碼進行有機的結(jié)合,形成”類”,其中數(shù)據(jù)和函數(shù)都是類的成員。封裝的目的是增強安全性和簡化編程,使用者不必了解具體的實現(xiàn)細(xì)節(jié),而只是要通過外部接口,特定的訪問權(quán)限來使用類的成員。封裝可以隱藏實現(xiàn)細(xì)節(jié),使得代碼模塊化。
繼承(inheritance):C++通過類派生機制來支持繼承。被繼承的類型稱為基類或超類,新產(chǎn)生的類為派生類或子類。保持已有類的特性而構(gòu)造新類的過程稱為繼承。在已有類的基礎(chǔ)上新增自己的特性而產(chǎn)生新類的過程稱為派生。繼承和派生的目的是保持已有類的特性并構(gòu)造新類。繼承的目的:實現(xiàn)代碼重用。派生的目的:實現(xiàn)代碼擴充。三種繼承方式:public、protected、private。
繼承時的構(gòu)造函數(shù):(1)、基類的構(gòu)造函數(shù)不能被繼承,派生類中需要聲明自己的構(gòu)造函數(shù);(2)、聲明構(gòu)造函數(shù)時,只需要對本類中新增成員進行初始化,對繼承來的基類成員的初始化,自動調(diào)用基類構(gòu)造函數(shù)完成;(3)、派生類的構(gòu)造函數(shù)需要給基類的構(gòu)造函數(shù)傳遞參數(shù);(4)、單一繼承時的構(gòu)造函數(shù):派生類名::派生類名(基類所需的形參,本類成員所需的形參):基類名(參數(shù)表) {本類成員初始化賦值語句;};(5)、當(dāng)基類中聲明有默認(rèn)形式的構(gòu)造函數(shù)或未聲明構(gòu)造函數(shù)時,派生類構(gòu)造函數(shù)可以不向基類構(gòu)造函數(shù)傳遞參數(shù);(6)、若基類中未聲明構(gòu)造函數(shù),派生類中也可以不聲明,全采用缺省形式構(gòu)造函數(shù);(7)、當(dāng)基類聲明有帶形參的構(gòu)造函數(shù)時,派生類也應(yīng)聲明帶形參的構(gòu)造函數(shù),并將參數(shù)傳遞給基類構(gòu)造函數(shù);(8)、構(gòu)造函數(shù)的調(diào)用次序:A、調(diào)用基類構(gòu)造函數(shù),調(diào)用順序按照它們被繼承時聲明的順序(從左向右);B、調(diào)用成員對象的構(gòu)造函數(shù),調(diào)用順序按照它們在類中的聲明的順序;C、派生類的構(gòu)造函數(shù)體中的內(nèi)容。
繼承時的析構(gòu)函數(shù):(1)、析構(gòu)函數(shù)也不被繼承,派生類自行聲明;(2)、聲明方法與一般(無繼承關(guān)系時)類的析構(gòu)函數(shù)相同;(3)、不需要顯示地調(diào)用基類的析構(gòu)函數(shù),系統(tǒng)會自動隱式調(diào)用;(4)、析構(gòu)函數(shù)的調(diào)用次序與構(gòu)造函數(shù)相反。
同名隱藏規(guī)則:當(dāng)派生類與基類中有相同成員時:(1)、若未強行指名,則通過派生類對象使用的是派生類中的同名成員;(2)、如要通過派生類對象訪問基類中被覆蓋的同名成員,應(yīng)使用基類名限定:基類名::數(shù)據(jù)成員名。
虛基類:作用:(1)、主要用來解決多繼承時可能發(fā)生的對同一基類繼承多次而產(chǎn)生的二義性問題;(2)、為最遠(yuǎn)的派生類提供唯一的基類成員,而不重復(fù)產(chǎn)生多次拷貝。
繼承、組合:組合是將其它類的對象作為成員使用,繼承是子類可以使用父類的成員方法。(1)、A繼承B,說明A是B的一種,并且B的所有行為對A都有意義;(2)、若在邏輯上A是B的“一部分”,則不允許B從A派生,而是要用A和其它東西組合出B;(3)、繼承屬于”白盒”復(fù)用,組合屬于”黑盒”復(fù)用。
?多態(tài)(Polymorphic)性可以簡單地概括為“一個接口,多種方法”,程序在運行時才決定調(diào)用的函數(shù)。C++多態(tài)性是通過虛函數(shù)來實現(xiàn)的,虛函數(shù)允許子類重新定義成員函數(shù),而子類重新定義父類的做法稱為覆蓋或者稱為重寫。而重載則是允許有多個同名的函數(shù),而這些函數(shù)的參數(shù)列表不同,允許參數(shù)個數(shù)不同,參數(shù)類型不同,或者兩者都不同。關(guān)于多態(tài),簡而言之就是用父類型別的指針指向其子類的實例,然后通過父類的指針調(diào)用實際子類的成員函數(shù)。
多態(tài)與非多態(tài)的實質(zhì)區(qū)別就是函數(shù)地址是早綁定還是晚綁定。如果函數(shù)的調(diào)用,在編譯器編譯期間就可以確定函數(shù)的調(diào)用地址,并產(chǎn)生代碼,是靜態(tài)的,就是說地址是早綁定的。而如果函數(shù)調(diào)用的地址不能在編譯期間確定,需要在運行時才確定,這就是屬于晚綁定。
封裝可以使得代碼模塊化,繼承可以擴展已存在的代碼,它們的目的都是為了代碼重用。而多態(tài)的目的則是為了接口重用。也就是說不論傳遞過來的究竟是哪個類的對象,函數(shù)都能夠通過同一個接口調(diào)用到適應(yīng)各自對象的實現(xiàn)方法。
最常見的用法就是聲明基類的指針,利用該指針指向任意一個子類對象,調(diào)用相應(yīng)的虛函數(shù),可以根據(jù)指向的子類的不同而實現(xiàn)不同的方法。如果沒有使用虛函數(shù)的話,即沒有利用C++多態(tài)性,則利用基類指針調(diào)用相應(yīng)的函數(shù)的時候,將總被限制在基類函數(shù)本身,而無法調(diào)用到子類中被重寫過的函數(shù)。因為沒有多態(tài)性,函數(shù)調(diào)用的地址將是一定的,而固定的地址將始終調(diào)用到同一個函數(shù),這就無法實現(xiàn)一個接口,多種方法的目的了。
純虛函數(shù)是在基類中聲明的虛函數(shù),它在基類中沒有定義,但要求任何派生類都要定義自己的實現(xiàn)方法。在基類中實現(xiàn)純虛函數(shù)的方法是在函數(shù)原型后加“= 0”。為了方便使用多態(tài)特性,常常需要在基類中定義虛函數(shù),在很多情況下,基類本身生成對象是不合情理的。為了解決這些問題,引入了純虛函數(shù)的概念,將函數(shù)定義為純虛函數(shù),則編譯器要求在派生類中必須予以重寫以實現(xiàn)多態(tài)性。同時含有純虛函數(shù)的類稱為抽象類,它不能生成對象。由于純虛函數(shù)所在的類中沒有它的定義,在該類的構(gòu)造函數(shù)和析構(gòu)函數(shù)中不允許調(diào)用純虛函數(shù),否則會導(dǎo)致程序運行錯誤,但其它成員函數(shù)可以調(diào)用純虛函數(shù)。
C++支持兩種多態(tài)性:(1)、編譯時多態(tài)性(靜態(tài)多態(tài),在編譯時就可以確定對象使用的形式):通過重載函數(shù)實現(xiàn);(2)、運行時多態(tài)性(動態(tài)多態(tài),其具體引用的對象在運行時才能確定):通過虛函數(shù)實現(xiàn)。
C++中,實現(xiàn)多態(tài)有以下方法:虛函數(shù)、抽象類、重載、覆蓋、模板。
函數(shù)重載(Overload):指在相同作用域里(如同一類中),函數(shù)同名不同參,返回值則不用理會,不同參可以是不同個數(shù),也可以是不同類型。效果:根據(jù)實參的個數(shù)和類型調(diào)用對應(yīng)的函數(shù)體。
函數(shù)覆蓋(Override)(函數(shù)重寫):指派生類中的函數(shù)覆蓋基類中的同名同參虛函數(shù),因此作用域不同。效果:基類指針或引用訪問虛函數(shù)時會根據(jù)實例的類型調(diào)用對應(yīng)的函數(shù)。
函數(shù)隱藏(Hide):對于子類中與基類同名的函數(shù),如果不是覆蓋那就成了隱藏。兩種情況:(1)、同名不同參;(2)、同名同參但基類不是virtual函數(shù)。
派生類的構(gòu)造函數(shù)使用說明:(1)、在派生類構(gòu)造函數(shù)中,只要基類不是僅使用無參的默認(rèn)構(gòu)造函數(shù),都要顯示的給出基類名稱參數(shù)表;(2)、基類沒有定義構(gòu)造函數(shù),派生類也可以不定義,使用默認(rèn)構(gòu)造函數(shù);(3)、基類有帶參構(gòu)造函數(shù),派生類必須定義構(gòu)造函數(shù)。
虛函數(shù)的重載函數(shù)仍是虛函數(shù)。在派生類重定義虛函數(shù)時必須有相同的函數(shù)原型,包括返回類型、函數(shù)名、參數(shù)個數(shù)、參數(shù)類型的順序必須相同。虛函數(shù)必須是類的成員函數(shù),不能為全局函數(shù),也不能為靜態(tài)函數(shù)。不能將友員說明為虛函數(shù),但虛函數(shù)可以是另一個類的友員。析構(gòu)函數(shù)可以是虛函數(shù),但構(gòu)造函數(shù)不能為虛函數(shù)。一般地講,若某類中定義有虛函數(shù),則其析構(gòu)函數(shù)也應(yīng)當(dāng)說明為虛函數(shù)。特別是在析構(gòu)函數(shù)需要完成一些有意義的操作,比如釋放內(nèi)存時,尤其應(yīng)當(dāng)如此。在類系統(tǒng)中訪問一個虛函數(shù)時,應(yīng)使用指向基類類型的指針或?qū)愵愋偷囊?#xff0c;以滿足運行時多態(tài)性的要求。當(dāng)然也可以像調(diào)用普通成員函數(shù)那樣利用對象名來調(diào)用一個函數(shù)。若在派生類中沒有重新定義虛函數(shù),則該類的對象將使用其基類中的虛函數(shù)代碼。
抽象類:如果一個類中至少有一個純虛函數(shù),那么這個類被稱為抽象類。抽象類不僅包括純虛函數(shù),也可包括虛函數(shù)。抽象類中的純虛函數(shù)可能是在抽象類中定義的,也可能是從它的抽象基類中繼承下來且重定義的。抽象類有一個重要特點,即抽象類必須用作派生其它類的基類,而不能用于直接創(chuàng)建對象實例。抽象類不能直接創(chuàng)建對象的原因是其中有一個或多個函數(shù)沒有定義,但仍可使用指向抽象類的指針支持運行時多態(tài)性。派生類中必須重載基類中的純虛函數(shù),否則它仍將被看作一個抽象類。從基類繼承來的純虛函數(shù),在派生類中仍是虛函數(shù)。
虛函數(shù)表:虛函數(shù)是通過一張?zhí)摵瘮?shù)表來實現(xiàn)的。簡稱為V-Table,在這個表中,主要是一個類的虛函數(shù)的地址表,這張表解決了繼承、覆蓋的問題,保證其真實反應(yīng)實際的函數(shù)。這樣,在有虛函數(shù)的類的實例中這個表被分配在了這個實例的內(nèi)存中,所以,當(dāng)我們用父類的指針來操作一個子類的時候,這張?zhí)摵瘮?shù)表就顯得有無重要了,它就像一個地圖一樣,指明了實際所應(yīng)該調(diào)用的函數(shù)。
一個多態(tài)的例子:
#include <iostream>
using namespace std;class A
{
public:void foo(){printf("1\n");}virtual void fun(){printf("2\n");}
};class B : public A
{
public:void foo(){printf("3\n");}void fun(){printf("4\n");}
};int main(void)
{A a;B b;A* p = &a;p->foo();//1p->fun();//2p = &b;p->foo();//1p->fun();//4B* ptr = (B*)&a;ptr->foo();//3ptr->fun();//2return 0;
}
另一個例子:
#include <iostream>
using namespace std;int main(void)
{class CA {public:virtual ~CA() {cout<<"delete CA"<<endl;}virtual int GetValue() {return 1;}};class CB : public CA{public:~CB() {cout<<"delete CB"<<endl;}virtual int GetValue() {return 2;}};CA* pA = new CB;cout<<pA->GetValue()<<endl;delete pA;/* result:2delete CBdelete CA*//*若父類CA中沒有將析構(gòu)函數(shù)定義為虛函數(shù),則result:2delete CA由結(jié)果看出,如果不將父類CA的析構(gòu)函數(shù)定義為虛函數(shù),則不會調(diào)用到子類的析構(gòu)函數(shù)*//*若父類CA中的成員函數(shù)GetValue沒有定義為虛函數(shù),則result:1delete CA*/return 0;
}
參考文獻(xiàn):
1、? http://www.docin.com/p-589112223.html
2、? http://blog.csdn.net/hackbuteer1/article/details/7475622
3、? http://blog.csdn.net/haoel/article/details/1948051
?
?
總結(jié)
以上是生活随笔為你收集整理的C++中的封装、继承、多态的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AES(Advanced Encrypt
- 下一篇: 设计模式之单例模式(Singleton)