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

正確理解C++的構(gòu)造函數(shù)和析構(gòu)函數(shù)

 更新時間:2021年06月30日 14:13:30   作者:ZhiboZhao  
在C++的學(xué)習(xí)中,可以把類當(dāng)作一個模具,類實例化出來的對象就是根據(jù)這個模具所產(chǎn)生的實體,對象看作是自己創(chuàng)建的一個新的數(shù)據(jù)類型。本文主要介紹了類對象通過拷貝函數(shù)進(jìn)行初始化,分析類對象的內(nèi)存模型,以及通過this指針實現(xiàn)更復(fù)雜的功能。最后介紹了析構(gòu)函數(shù)的基礎(chǔ)知識

一、構(gòu)造函數(shù)

首先,由于類只是一個模板,因此我們在定義類時無法對成員變量初始化,比如下面代碼就是錯誤的:

class circle{
public:
    int m_L = 20;	// Error:不允許使用數(shù)據(jù)成員初始值設(shè)定項
};

因此,初始化只能發(fā)生在類創(chuàng)建對象的過程中,但是由于訪問權(quán)限的原因,無法在類外訪問某些成員變量,因此下面這種做法有時候是無效的:

circle C1;	// 實例化一個對象 C1
C1.m_L = 20;	// 通過創(chuàng)建的對象,來給對應(yīng)變量初始化,但是如果m_L是private訪問權(quán)限,則失效

為了解決這個問題,讓程序員能像使用標(biāo)準(zhǔn)數(shù)據(jù)類型一樣適用對象,在類內(nèi)提供了一個特殊的成員函數(shù)——“構(gòu)造函數(shù)”,專門用于在創(chuàng)建對象時初始化類對象。之所以說它特殊,是因為C++已經(jīng)自動為構(gòu)造函數(shù)提供了名稱和使用語法,程序員只需要提供方法的定義即可,即:類名(形參列表)。具體來說,構(gòu)造函數(shù)的定義如下:

class circle{
public:
    int m_L;
public: //成員函數(shù)(方法)
    circle(const int a)	//通過構(gòu)造函數(shù)對成員變量進(jìn)行賦值
    {
        m_L = a;
    }
};

circle C1(20);	//調(diào)用格式
cout << "C1.m_L:" << C1.m_L <<endl;

看上去似乎很簡單,但是由于構(gòu)造函數(shù)也是函數(shù),因此所有C++中的形參傳遞方式,函數(shù)特性以及函數(shù)調(diào)用方法都能用于構(gòu)造函數(shù)。 如前文所講,C++會自動給類添加一個空的構(gòu)造函數(shù),但是如果自己在類中實現(xiàn)了有參構(gòu)造函數(shù),編譯器便不再提供無參構(gòu)造函數(shù)。舉例如下:

class circle{
public:
    int m_L;
public: //成員函數(shù)(方法)
    circle(const int a)	//通過構(gòu)造函數(shù)對成員變量進(jìn)行賦值
    {
        m_L = a;
    }
};

circle C1(20);	//調(diào)用格式正確,能夠通過構(gòu)造函數(shù)賦值
circle C2; 		//錯誤,自己定義了有參構(gòu)造函數(shù),不再提供無參構(gòu)造函數(shù)

構(gòu)造函數(shù)可以重載,接著上面的例子,如果重載一個空的構(gòu)造函數(shù),那么兩個調(diào)用格式都正確:

class circle{
public:
    int m_L;
public: //成員函數(shù)(方法)
    circle(){}	// 空構(gòu)造函數(shù)
    circle(const int a)	//通過構(gòu)造函數(shù)對成員變量進(jìn)行賦值
    {
        m_L = a;
    }
};

circle C1(20);	//調(diào)用格式正確,能夠通過構(gòu)造函數(shù)賦值
circle C2; 		//正確,可以通過重載的空構(gòu)造函數(shù)實現(xiàn)初始化

構(gòu)造函數(shù)的參數(shù)不僅可以是標(biāo)準(zhǔn)數(shù)據(jù)類型,也可以是類。眾所周知,在數(shù)值作為函數(shù)參數(shù)進(jìn)行傳遞的時候,會重新拷貝出來一份數(shù)據(jù)作為參數(shù)傳遞用完即銷毀,這種方式不僅浪費了內(nèi)存空間,而且無法修改原始數(shù)據(jù)。為了結(jié)合這兩者之間的優(yōu)點,于是經(jīng)常采取引用作為函數(shù)的參數(shù)。雖然引用是指針的一種特殊情況,但是指針太過于靈活,并且引用在形式上引用與普通的變量地用法并沒有什么區(qū)別,因此使用起來更加方便。

class circle{
public:
    int m_L;
public: //成員函數(shù)(方法)
    circle(){}	// 空構(gòu)造函數(shù)
    circle(const int a)	//通過構(gòu)造函數(shù)對成員變量進(jìn)行賦值
    {
        m_L = a;
    }
    //引用作為函數(shù)參數(shù)傳遞,并用const修飾,節(jié)省空間的同時避免修改原數(shù)據(jù)
    circle(const circle& sub_circle)	
    {
        m_L = sub_circle.m_L;
    }
};

circle C1(20);	//調(diào)用格式正確,能夠通過構(gòu)造函數(shù)賦值
circle C2(C1); 	//正確,可以通過拷貝構(gòu)造函數(shù)進(jìn)行初始化

二、C++類的內(nèi)存模型

C++中,一個類包括:

  • 成員變量:靜態(tài)成員變量和普通成員變量
  • 成員函數(shù):靜態(tài)成員函數(shù)和普通成員函數(shù)

雖然為了集成,我們將其寫到一個類里面,但是只有普通成員變量真正屬于類的對象,類的所有對象共享一份靜態(tài)成員函數(shù),靜態(tài)成員變量和普通成員函數(shù)。畫出了內(nèi)存模型,如下圖所示:

為了進(jìn)一步理解,我們舉例如下:

2.1、只定義成員函數(shù)

class person{
public:
    // 定義一個空的構(gòu)造函數(shù)
	person(int m_age, int m_ID){
	}
};
person p1(10, 20);
cout << "p1 所占的空間為:" << sizeof(p1) << endl;

輸出結(jié)果為:

p1 所占的空間為:1

這個題目在《劍指offer》一書中也提到過,由空類實例化出來的對象所占的內(nèi)存空間是1個而不是0個字節(jié),因為編譯其給對象 p1 分配了一個地址,來表示不同的對象存儲在不同的地址空間,因此占用1個字節(jié)。

2.2、往空類中添加靜態(tài)成員變量

class person{
    static int age; //靜態(tài)成員變量,存在全局區(qū),不屬于類對象的一部分
    static int ID;  //靜態(tài)成員變量,存在全局區(qū),不屬于類對象的一部分
public:
    // 定義一個空的構(gòu)造函數(shù)
	person(int m_age, int m_ID){
	}
};
person p1(10, 20);
cout << "p1 所占的空間為:" << sizeof(p1) << endl;

輸出結(jié)果為:

p1 所占的空間為:1

當(dāng)向類中加入了成員函數(shù)與靜態(tài)成員變量時,類的實例化對象仍然只占用1個字節(jié)的空間,足以證明這些函數(shù)和變量并不是類對象的一部分。

2.3、再加入非靜態(tài)成員變量

class person
{
    static int age; //靜態(tài)成員變量,存在全局區(qū),不屬于類對象的一部分
    static int ID;  //靜態(tài)成員變量,存在全局區(qū),不屬于類對象的一部分
    int a;	//非靜態(tài)成員變量,存在棧區(qū),屬于類對象的一部分
public:
	person(int m_age, int m_ID){
	}
};

輸出結(jié)果為:

p 所占的空間為:4

因此當(dāng)向類中加入了非靜態(tài)成員變量時,類的實例化對象占用4個字節(jié)的空間,可以說明,非靜態(tài)變量屬于類對象的一部分。綜上:同一個類所有實例化出來的對象共享同一份靜態(tài)成員變量,所以一改全改。既然同一個類的不同對象共享同一份成員函數(shù),那么成員函數(shù)怎么區(qū)分該訪問哪個對象的普通成員變量呢?

三、this指針

接著上一小節(jié)的問題,this指針為上述問題提供了一個完美的解決方案,它指向用來調(diào)用成員函數(shù)的對象(被當(dāng)作參數(shù)隱式地傳遞給成員函數(shù)),我們通過一張圖來理解它:

此外,this指針的另一個用途是當(dāng)成員函數(shù)需要返回對象時,用 return *this; 或者 return this,這種做法能夠?qū)崿F(xiàn)鏈?zhǔn)骄幊?。比如?/p>

p2.addPerson(p1).addPerson(p1);

首先,對象 p2 調(diào)用成員函數(shù) addPerson(p1) ,其返回值繼續(xù)調(diào)用 addPerson(p1),此時返回值就必須也是 person 類型才可以,因此使用 this 指針可以完成需求。先來看第一個例子:

class person{
public:
	int age;
	person(int age)
	{
		this->age = age; // this指針區(qū)分調(diào)用者
	}
	// 返回值為person類型,且參數(shù)加上了const限制,防止修改原數(shù)據(jù)
	person addPerson(const person& p)
	{
		this->age += p.age;	// 主要實現(xiàn)兩個類對象年齡的相加
		return *this;	// 由于返回值是person,因此返回 *this
	}
};

person p1(20);
person p2(10);
person p3 = p2.addPerson(p1).addPerson(p1);
cout << "p1 age:" << p1.age << endl;
cout << "p2 age:" << p2.age << endl;
cout << "p3 age:" << p3.age << endl;

首先,通過構(gòu)造函數(shù)分別對 p1,p2 賦了初值,然后 p2 調(diào)用函數(shù) addPerson(p1) 修改自身的變量 age 。**由于函數(shù)通過值傳遞的方式返回 person 類型,所以將整個 person 類型復(fù)制了一份返回,返回值繼續(xù)調(diào)用 addPerson(p1), **最后的結(jié)果賦值給了新的對象 p3。所以輸出結(jié)果為:

p1 age:20

p2 age:30

p3 age:50

但是如果函數(shù) addPerson() 修改為:

person& addPerson(const person& p)
{
    this->age += p.age;	// 主要實現(xiàn)兩個類對象年齡的相加
    return *this;	// 雖然返回值是person&,返回值的類型也是 *this
}

person p1(20);
person p2(10);
person p3 = p2.addPerson(p1).addPerson(p1);
cout << "p1 age:" << p1.age << endl;
cout << "p2 age:" << p2.age << endl;
cout << "p3 age:" << p3.age << endl;

與上例唯一的區(qū)別就在于返回值的類型變成了引用,那么每次返回的就變成了該對象本身,而非在值傳遞中拷貝出來的那一份數(shù)據(jù)。那么輸出就變成了:

p1 age:20

p2 age:50

p3 age:50

四、析構(gòu)函數(shù)

用構(gòu)造函數(shù)創(chuàng)建對象后,程序負(fù)責(zé)跟蹤該對象,知道其過期為止。當(dāng)對象過期時,程序自動調(diào)用析構(gòu)函數(shù)完成清理工作。與構(gòu)造函數(shù)一樣,C++默認(rèn)提供了一個空的析構(gòu)函數(shù),定義為:~類名( )。由于開辟在棧區(qū)的變量程序會自動釋放,因此不需要析構(gòu)函數(shù)執(zhí)行清理工作,但是當(dāng)程序員在堆區(qū)開辟空間時,需要手動執(zhí)行清理工作,這時候需要析構(gòu)函數(shù)來釋放堆區(qū)內(nèi)存。比如:

~person()
{
	// 在析構(gòu)函數(shù)內(nèi)寫入需要執(zhí)行的代碼
	cout << "調(diào)用析構(gòu)函數(shù)" << endl;
}
person p1(20);
person p2(10);	// 在生命周期結(jié)束后自動調(diào)用析構(gòu)函數(shù)執(zhí)行清理工作

輸出為:

調(diào)用析構(gòu)函數(shù)

調(diào)用析構(gòu)函數(shù)

以上就是正確理解C++的構(gòu)造函數(shù)和析構(gòu)函數(shù)的詳細(xì)內(nèi)容,更多關(guān)于C++ 構(gòu)造函數(shù) 析構(gòu)函數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 簡單分析C++指針的操作和運(yùn)算

    簡單分析C++指針的操作和運(yùn)算

    這篇文章主要介紹了簡單分析C++指針的操作和運(yùn)算的相關(guān)資料,需要的朋友可以參考下
    2015-07-07
  • C語言實現(xiàn)簡單三子棋游戲

    C語言實現(xiàn)簡單三子棋游戲

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)簡單三子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • C++缺省參數(shù)、函數(shù)重載與引用深入解析

    C++缺省參數(shù)、函數(shù)重載與引用深入解析

    缺省參數(shù)函數(shù)重載以及引用的出現(xiàn)是為了補(bǔ)充C語言語法的不足以及對C語言設(shè)計不合理的地方進(jìn)行優(yōu)化,引用的出現(xiàn)大大降低了我們學(xué)習(xí)C語言時相對于指針的難度,也便于我們更好的理解和使用,感興趣的朋友一起看看吧
    2024-04-04
  • C語言實現(xiàn)最全自動售貨機(jī)

    C語言實現(xiàn)最全自動售貨機(jī)

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)最全自動售貨機(jī),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 深入分析C++中類的大小

    深入分析C++中類的大小

    本篇文章深入分析了C++中類的大小問題。需要的朋友參考下
    2013-05-05
  • OpenCV圖像分割中的分水嶺算法原理與應(yīng)用詳解

    OpenCV圖像分割中的分水嶺算法原理與應(yīng)用詳解

    這篇文章主要為大家詳細(xì)介紹了OpenCV圖像分割中的分水嶺算法原理與應(yīng)用,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • c++可變參數(shù)模板使用示例源碼解析

    c++可變參數(shù)模板使用示例源碼解析

    這篇文章主要為大家介紹了c++可變參數(shù)模板使用示例源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • C++實現(xiàn)Linux下彈出U盤的方法

    C++實現(xiàn)Linux下彈出U盤的方法

    這篇文章主要介紹了C++實現(xiàn)Linux下彈出U盤的方法,實例分析了C++在Linux平臺上進(jìn)行IO操作的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • C語言實現(xiàn)動態(tài)版通訊錄的示例代碼

    C語言實現(xiàn)動態(tài)版通訊錄的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用C語言實現(xiàn)一個簡單的動態(tài)版通訊錄,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)C語言有一定幫助,需要的可以參考一下
    2022-08-08
  • c++ 前自增/后自增操作符效率分析

    c++ 前自增/后自增操作符效率分析

    這篇文章主要介紹了c++ 前自增/后自增操作符效率分析,幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下
    2021-01-01

最新評論