欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++中的封裝、繼承、多態(tài)理解

 更新時間:2020年01月30日 20:47:33   作者:fengbingchun  
這篇文章主要介紹了C++中的封裝、繼承、多態(tài)介紹,需要的朋友可以參考下

封裝(encapsulation):就是將抽象得到的數(shù)據(jù)和行為(或功能)相結(jié)合,形成一個有機(jī)的整體,也就是將數(shù)據(jù)與操作數(shù)據(jù)的源代碼進(jìn)行有機(jī)的結(jié)合,形成”類”,其中數(shù)據(jù)和函數(shù)都是類的成員。封裝的目的是增強(qiáng)安全性和簡化編程,使用者不必了解具體的實現(xiàn)細(xì)節(jié),而只是要通過外部接口,特定的訪問權(quán)限來使用類的成員。封裝可以隱藏實現(xiàn)細(xì)節(jié),使得代碼模塊化。

繼承(inheritance):C++通過類派生機(jī)制來支持繼承。被繼承的類型稱為基類或超類,新產(chǎn)生的類為派生類或子類。保持已有類的特性而構(gòu)造新類的過程稱為繼承。在已有類的基礎(chǔ)上新增自己的特性而產(chǎn)生新類的過程稱為派生。繼承和派生的目的是保持已有類的特性并構(gòu)造新類。繼承的目的:實現(xiàn)代碼重用。派生的目的:實現(xiàn)代碼擴(kuò)充。三種繼承方式:public、protected、private。

繼承時的構(gòu)造函數(shù):(1)、基類的構(gòu)造函數(shù)不能被繼承,派生類中需要聲明自己的構(gòu)造函數(shù);(2)、聲明構(gòu)造函數(shù)時,只需要對本類中新增成員進(jìn)行初始化,對繼承來的基類成員的初始化,自動調(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)、若未強(qiáng)行指名,則通過派生類對象使用的是派生類中的同名成員;(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)用的地址不能在編譯期間確定,需要在運行時才確定,這就是屬于晚綁定。

封裝可以使得代碼模塊化,繼承可以擴(kuò)展已存在的代碼,它們的目的都是為了代碼重用。而多態(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ū)愵愋偷囊?,以滿足運行時多態(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();//1
	p->fun();//2
 
	p = &b;
	p->foo();//1
	p->fun();//4
 
	B* ptr = (B*)&a;
	ptr->foo();//3
	ptr->fun();//2
 
	return 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:
		2
		delete CB
		delete CA
	*/
	/*若父類CA中沒有將析構(gòu)函數(shù)定義為虛函數(shù),則result:
		2
		delete CA
		由結(jié)果看出,如果不將父類CA的析構(gòu)函數(shù)定義為虛函數(shù),則不會調(diào)用到子類的析構(gòu)函數(shù)
	*/
	/*若父類CA中的成員函數(shù)GetValue沒有定義為虛函數(shù),則result:
		1
		delete CA
	*/
 
	return 0;
}

對C++繼承,封裝,多態(tài)的理解

用了C++一段時間,感覺對C++慢慢有了一點認(rèn)識,在這和大家分享一下。
C++是一款面向?qū)ο蟮恼Z言,擁有面向?qū)ο笳Z言的三大核心特性:繼承,封裝,多態(tài)。每一個特性的良好理解與使用都會為我們的編程帶來莫大的幫助。下面我就這三個特性講一下我對C++的理解。

繼承

      學(xué)過面向?qū)ο笳Z言的人基本都可以理解什么是繼承,但我們?yōu)槭裁匆褂美^承?
      很多人說繼承可以使代碼得到良好的復(fù)用,當(dāng)然這個是繼承的一個優(yōu)點,但代碼復(fù)用的方法除了繼承還有很多,而且有些比繼承更好。我認(rèn)為使用繼承最重要的原因是繼承可以使整個程序設(shè)計更符合人們的邏輯,從而方便的設(shè)計出想要表達(dá)的意思。比如我們要設(shè)計一堆蘋果,橘子,梨等水果類,使用面向?qū)ο蟮姆椒?,我們首先會抽象出一個水果的基類,而后繼承這個基類,派生出具體的水果類。如果要設(shè)計的水果很多,我們還可以在水果基類基礎(chǔ)上,繼續(xù)生成新的基類,比如熱帶水果類,溫帶水果類,寒帶水果類等,而后再繼承這些基類。這樣的設(shè)計思想就相當(dāng)于人類的分類思想,簡單易懂,而且設(shè)計出來的程序?qū)哟畏置鳎菀渍莆铡?br />       既然繼承這么好,那該如何使用繼承?
      繼承雖好但不能濫用,否則設(shè)計出來的程序會雜亂不堪。根據(jù)上面的介紹,可以發(fā)現(xiàn)繼承主要用來定義一個東西是什么,比如熱帶水果是水果,菠蘿是熱帶水果等,即繼承主要用來設(shè)計一個程序的類的框架,將所要設(shè)計的東西用繼承來設(shè)立一個基本結(jié)構(gòu)。如果想為一個類添加一個行為或格外的功能,最好是使用組合的方式。如果想了解組合的方式,可以看一下比較著名的策略模式。

封裝

      封裝是什么?
      在C++中,比較狹隘的解釋就是將數(shù)據(jù)與操作數(shù)據(jù)的方法放在一個類中,而后給每個成員設(shè)置相應(yīng)的權(quán)限。從大一點的角度來說,封裝就是將完成一個功能所需要的所有東西放在一起,對外部只開放調(diào)用它的接口。
       為什么要封裝?
       我認(rèn)為模塊化設(shè)計是封裝的本質(zhì)原因。
       對軟件設(shè)計或其他工程設(shè)計,特別是比較復(fù)雜的工程,一般都是模塊化設(shè)計。模塊化設(shè)計的好處就是可以將一個復(fù)雜的系統(tǒng)拆分成不同的模塊。每一個模塊又可以獨立的設(shè)計,調(diào)試,這就讓多人一起做一個復(fù)雜的工程成為現(xiàn)實。如果想做到模塊化設(shè)計,封裝是不可缺少的一部分。一個好的模塊,比如一塊inter的CPU芯片,它有強(qiáng)大的功能,雖然我們不知道它內(nèi)部是如何實現(xiàn)的,但卻可以很好的使用它。 

多態(tài)

        什么是多態(tài)?
        多態(tài)簡單的說就是“一個函數(shù),多種實現(xiàn)”,或是“一個接口,多種方法”。多態(tài)性表現(xiàn)在程序運行時根據(jù)傳入的對象調(diào)用不同的函數(shù)。
        C++的多態(tài)是通過虛函數(shù)來實現(xiàn)的,在基類中定義一個函數(shù)為虛函數(shù),該函數(shù)就可以在運行時,根據(jù)傳入的對象調(diào)用不同的實現(xiàn)方法。而如果該函數(shù)不設(shè)為虛函數(shù),則在調(diào)用的過程中調(diào)用的函數(shù)就是固定的。比如下面一個例子

//
//定義一個Duck基類,而后繼承Duck派生出一個RedHandDuck類。
//其中display()方法,第一次運行設(shè)為普通函數(shù),第二次設(shè)為虛函數(shù)
 
#include "iostream"
 
class Duck {
 
public:
	Duck(){}
	~Duck(){}
 
	//定義一個虛函數(shù)display
	virtual void display(){
 
		std::cout<<" I am a Duck !"<<std::endl;
	}
};
 
class RedHandDuck:public Duck{
 
public:
	RedHandDuck(){}
	~RedHandDuck(){}
 
	//重寫display
	void display(){
 
		std::cout<<" I am a RedHandDuck !"<<std::endl;
	}
};
 
int main(){
 
	RedHandDuck* duck1 = new RedHandDuck();
	Duck* duck2 = duck1;
 
	duck1->display();
	duck2->display();
 
	std::getchar();
}

第一次運行結(jié)果(不使用虛函數(shù)):

第二次運行結(jié)果(使用虛函數(shù)):

由結(jié)果可以看到,由于虛函數(shù)的使用,Duck對象(可以理解為接口),調(diào)用的display()方法是根據(jù)傳入的對象決定的。這就實現(xiàn)了“一個接口,多種方法”。

從網(wǎng)上看到一個關(guān)于多態(tài)的介紹,非常精辟,分享給大家

  多態(tài)與非多態(tài)的實質(zhì)區(qū)別就是函數(shù)地址是早綁定還是晚綁定。如果函數(shù)的調(diào)用,在編譯器編譯期間就可以確定函數(shù)的調(diào)用地址,并生產(chǎn)代碼,是靜態(tài)的,就是說地址是早綁定的。而如果函數(shù)調(diào)用的地址不能在編譯器期間確定,需要在運行時才確定,這就屬于晚綁定。

相關(guān)文章

  • C語言中enum關(guān)鍵字的實現(xiàn)示例

    C語言中enum關(guān)鍵字的實現(xiàn)示例

    這篇文章主要介紹了C語言中enum關(guān)鍵字的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • C語言植物大戰(zhàn)數(shù)據(jù)結(jié)構(gòu)快速排序圖文示例

    C語言植物大戰(zhàn)數(shù)據(jù)結(jié)構(gòu)快速排序圖文示例

    這篇文章主要為大家介紹了C語言植物大戰(zhàn)數(shù)據(jù)結(jié)構(gòu)快速排序圖文示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • C/C++哈希表優(yōu)化LeetCode題解997找到小鎮(zhèn)的法官

    C/C++哈希表優(yōu)化LeetCode題解997找到小鎮(zhèn)的法官

    這篇文章主要為大家介紹了C/C++哈希表優(yōu)化題解997找到小鎮(zhèn)的法官示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • C++ 實現(xiàn)L2-002 鏈表去重

    C++ 實現(xiàn)L2-002 鏈表去重

    這篇文章主要介紹了C++ 實現(xiàn)L2-002 鏈表去重,本文通過簡要的案例,解題思路講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++?Primer學(xué)習(xí)記錄之變量

    C++?Primer學(xué)習(xí)記錄之變量

    這篇文章主要為大家介紹了C++Primer之變量,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • C/C++實現(xiàn)重置文件時間戳

    C/C++實現(xiàn)重置文件時間戳

    這篇文章主要為大家詳細(xì)介紹了C/C++實現(xiàn)重置文件時間戳的相關(guān)資料,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以參考一下
    2023-11-11
  • c++實現(xiàn)簡單的線程池

    c++實現(xiàn)簡單的線程池

    這里給大家介紹了C++中對于pthread線程的一個簡單應(yīng)用以及使用繼承CDoit,實現(xiàn)其中的start和end,有需要的小伙伴可以參考下
    2015-11-11
  • C++中指向結(jié)構(gòu)體變量的指針

    C++中指向結(jié)構(gòu)體變量的指針

    結(jié)構(gòu)體變量的指針就是該變來那個所占據(jù)的內(nèi)存段的起始地址??梢栽O(shè)一個指針變量,來指向一個結(jié)構(gòu)體變量,此時該指針變量的值是結(jié)構(gòu)體變量的起始地址
    2013-10-10
  • C語言位運算和sizeof運算符詳解

    C語言位運算和sizeof運算符詳解

    這篇文章主要介紹了C語言位運算和sizeof運算符詳解的相關(guān)資料,這里提供了詳細(xì)的知識要點,并附簡單代碼示例,需要的朋友可以參考下
    2016-11-11
  • C語言實現(xiàn)求解最小公倍數(shù)的算法示例

    C語言實現(xiàn)求解最小公倍數(shù)的算法示例

    這篇文章主要為大家介紹了C語言如何實現(xiàn)求解任意兩個正整數(shù)的最小公倍數(shù),文中采用了窮舉法和定理法。感興趣的小伙伴快來跟隨小編一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12

最新評論