鑽進魔術師的帳篷看對象的前世今生-------------類的6個默認成員函數


介紹類的6個成員函數之前,我們先來看一下this指針

this指針

this 指針是成員函數里面的一個隱藏指針,指向了調用該函數的對象本身。

this指針特性:

(1)this指針的類型為:類類型* const

(2)this指針並不是對象本身的一部分,不影響sizeof結果

(3)this指針的作用域在類“成員函數”內部

(4)this指針是”類成員函數”的第一個默認隱含參數,編譯器自動維護傳遞,類編寫者不能顯式傳遞 

(5)只有在類的非靜態成員函數中才可以使用this指針,其它任何函數都不可以

(6)this指針不能在初始化列表中使用

(7)當通過this指針訪問數據成員時,this指針不能為空

class Test
{
public:
	void FunTest()
	{
		cout << "FunTest():" << this << endl;
		//若不進行注釋程序會編譯錯誤,this指針為空,不能使用this指針來訪問數據成員
		/*cout << this->_a << endl;*/
	}
private:
	int _a;
};

int main()
{
	Test* pt = NULL;
	pt->FunTest();
	return 0;
}

this指針是使用__thiscall調用約定的

(1)__thiscall只能夠用在類的成員函數

(2) 參數從右向左壓棧 

(3)如果參數個數確定,this指針通過ecx傳遞給被調用者;如果參數不確定(_cdecl),this指針在所有參數被壓棧后壓入堆棧 

(4)對參數個數不定的,調用者清理堆棧,否則函數自己清理堆棧

類的6個默認的成員函數


構造函數:

(1)概念:構造函數是一個特殊的成員函數,名字和類名相同無返回值類型,創建類對象時由編譯器自動調用在對象的生命周期內只調用一次,保證每個數據成員都有一個合適的初始值

class Date
{
public:
	//初始化列表
	Date(int year,int month,int day)
		:_year(year),_month(month),_day(day)
	{
		cout << "Date(int):" << this << endl;
	}
private:
		int _year;
		int _month;
		int _day;
};

int main()
{
	Date d(2018, 6, 14);
	return 0;
}

(2)特性:1)函數名與類名相同 ,沒有返回值 2) 新對象被創建時,由編譯器自動調用,且在對象的聲明周期內僅調用 一次 3)構造函數可以重載,實參決定了調用哪個構造函數 4)無參構造函數和帶有缺省值的構造函數都認為是缺省的構造函數,並 且缺省的構造函數只能有一個 5)有初始化列表6) 如果沒有顯式定義時,編譯器會合成一個默認的構造函數7) 構造函數不能用const修飾8)構造函數不能為虛函數

編譯器在什么時候合成默認構造函數?

1)有一個A類,A類中包含缺省的構造函數

2)有一個B類,包含了A類的對象,並且B類沒有顯式定義自己的構造函數

在這種情況下系統必須為B類合成默認構造函數,目的就是為了構造B對象中包含的A對象

如下:

class Time
{
public:
	Time(int hour=8,int minute=2,int second=45)
		:_hour(hour),_minute(minute),_second(second)
	{}

private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
private:
		int _year;
		int _month;
		int _day;
		Time _t;
};

int main()
{
	Date d;//會調用系統合成的構造函數
	return 0;
}

(3)對象初始化

初始化列表:以一個冒號開始,接着是一個以逗號分隔的數據成員列表, 每個”成員變量”后面跟一個放在括號中的初始值或表達式  
注意:

1)每個成員在初始化列表中只能出現一次

因為初始化的時候需要划分空間,所以只能出現一次 

2)初始化列表僅用於初始化類的數據成員,並不指定這些數據成員的初始化順序,數據成員在類中定義順序就是在參數列表中的初始化順序,盡量避免使用成員初始化成員,成員的初始化順序好和成員的定義 順序保持一致

3)類中包含以下成員,一定要放在初始化列表位置進行初始化:

引用成員變量     const成員變量     類類型成員(該類有非缺省的構造函數)

類中包含類類型成員一定要放在初始化列表位置進行初始化:即A類中有非缺省的構造函數,B類中有構造函數,數據成員包含A類對象。

(4)構造函數作用

1)構造&初始化對象 

2)類型轉換   對於單個參數構造函數,可以將其接受參數轉化成類類型對象。用 explicit修飾構造函數,抑制由構造函數定義的隱式轉換,explicit 關鍵字類內部的構建聲明上,在類的定義體外部的定義上不再重復,如:

class Date
{
public:
	//構造函數用explicit修飾可以避免類型轉換問題
	 Date(int year)
		:_year(year)
	{
		cout << "Date(int)" << this << endl;
	}
private:
	int _year;
	int _month;
	int	_day;
};

int main()
{
	Date d1(2018);
	d1 = 2019;//用2019來構造一個臨時對象,賦給d1
	return 0;
}

拷貝構造函數

class Date
{
public:
	Date(int year,int month,int day)
		:_year(year),_month(month),_day(day)
	{
		cout << "Date(int):" << this << endl;
	};

	//拷貝構造函數
	Date(const Date& d)
		:_year(d._year)
		,_month(d._month)
		,_day(d._day)
	{
		cout << "Date(const Date&):" << this << endl;
	};
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2018, 6, 14);
	Date d2(d1);
	return 0;
}

(1)概念

只有單個形參,而且該形參是對本類類型對象的引用(常用const修飾),這 樣的構造函數稱為拷貝構造函數。拷貝構造函數是特殊的構造函數,創建 對象時使用已存在的同類對象來進行初始化,由編譯器自動調用

(2)特征

1)是構造函數的重載,構造函數的性質拷貝構造函數均滿足 

2)參數必須使用類類型對象引用傳遞(為什么?) 

若用值傳遞傳參時,就會調用拷貝構造函數來構造臨時變量,形成遞歸

3)如果沒有顯式定義,系統會自動合成一個默認的拷貝構造函數。默認 的拷貝構造函數會依次拷貝類的數據成員完成初始化

析構函數

(1)概念

析構函數:與構造函數功能相反,在對象被銷毀時,由編譯器自動調用,完成類 的一些資源清理和汕尾工作

(2)特性

1)析構函數在類名(即構造函數名)加上字符~ 

2)析構函數無參數無返回值

3) 一個類有且只有一個析構函數。若未顯示定義,系統會自動生成缺省的析構函數 

4)對象生命周期結束時,C++編譯系統系統自動調用析構函數 

注意析構函數體內並不是刪除對象,而是做一些清理工作


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com