首頁 > 軟體

C++類別的構造與解構特點及作用詳解

2022-10-20 14:03:18

一、類別建構函式

什麼是建構函式

和類具有相同名稱,並且沒有返回值型別的函數,就是類別建構函式

概念模糊、直接舉例:

#include <stdio.h>
#include <windows.h>
struct Test
{
    Test()        // 和類具有相同的名、並且沒有返回值
    {
    }
};
int main()
{
    return 0;
}

建構函式的特點

直接先來說特點吧,然後論證:

1、建構函式在定義物件的時候被呼叫

2、建構函式可以進行函數過載,可以有很多個

3、建立物件時預設呼叫的是無參構造

證明1:

建構函式在定義物件的時候被呼叫;

論證如下:

#include <stdio.h>
struct Test
{
	Test()
	{
		printf("你呼叫了建構函式n");		// 此處下斷點、如果該函數被呼叫肯定會停下來。
	}
};
int main()
{
	Test te;
	printf("接力n");
	return 0;
}

我們在Test()構造的輸出語句上加斷點、當程式呼叫Test的printf肯定會停下來,這個時候我們轉到反組合,單步步過、直到函數返回之後,就能知到剛剛是在哪裡呼叫的建構函式了

vs2010:F7編譯、F5偵錯、ALT+8反組合:

F10一直執行到返回:

這裡編譯器做了優化,可以直接看出來是在Test定義物件的時候呼叫了構造。

證明2:

建構函式可以進行函數過載,可以有很多個;

論證如下:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你呼叫了建構函式n");		// 此處下斷點、如果該函數被呼叫肯定會停下來。
	}
	Test(int a)
	{
		printf("過載%dn",a);
	}
	Test(int a, int b)
	{
		printf("過載%dn",a+b);
	}
};
int main()
{
	Test te;
	Test te1(1);
	Test te2(1,1);			// 注意、呼叫有參的建構函式時,需要傳遞引數
	system("pause");
	return 0;
}

過載了兩個,注意:呼叫有引數的構造時,需要傳遞引數。

執行可以通過:

證明3:

建立物件時預設呼叫的是無參構造;

論證如下:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test(int a)
	{
		printf("過載%dn",a);
	}
	Test(int a, int b)
	{
		printf("過載%dn",a+b);
	}
};
int main()
{
	Test te;            // 普通定義物件的方式、不帶引數
	system("pause");
	return 0;
}

首先我們刪除無參構造,看看能否編譯通過:

不可以

然後刪除有參構造:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你呼叫了建構函式n");		// 此處下斷點、如果該函數被呼叫肯定會停下來。
	}
};
int main()
{
	Test te;
	system("pause");
	return 0;
}

可以

全部都加上:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你呼叫了建構函式n");		// 此處下斷點、如果該函數被呼叫肯定會停下來。
	}
	Test(int a)
	{
		printf("過載%dn",a);
	}
	Test(int a, int b)
	{
		printf("過載%dn",a+b);
	}
};
int main()
{
	Test te;
	system("pause");
	return 0;
}

執行結果:

這已經證明了,Test te;平常這樣定義物件的時候,呼叫的是無參構造。如果需要呼叫有參構造,必須傳入引數;

這個特點很簡單、有參函數肯定要傳參嘛,所以定義物件的時候肯定要傳入引數啊;

但是這裡建議無論什麼時候寫類,最好還是寫上無參構造,哪怕什麼都不做也儘量寫上,避免不必要的麻煩。

建構函式的作用

一般用於初始化類的成員

如下:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	int x;
	int y;
	int z;
	Test()
	{
	}
	Test(int x,int y,int z)						// 建構函式初始化物件
	{
		this->x = x;
		this->y = y;
		this->z = z;	
	}
};
int main()
{
	Test te;
	Test te1(1,2,3);							// 定義物件並呼叫有參構造進行初始化
	printf("%d %d %dn",te1.x,te1.y,te1.z);		// 輸出看看是否初始化成功
	system("pause");
	return 0;
}

執行如下:

初始化成功。

二、類的解構函式

什麼是解構函式

類別建構函式名前加上'~'這個符號,就是類的解構函式

概念模糊、程式碼如下:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你呼叫了一次類別建構函式n");
	}
	~Test()
	{
		printf("你呼叫了一次類的解構函式n");
	}
};
int main()
{
	Test te;
	// system("pause");        // 這裡就不要讓程式停下來了,不然解構不了
	return 0;
}

~Test(){}就這個樣子

解構函式的特點

依然直接先來說特點,然後論證:

1、解構函式不能過載、不能有引數

2、解構函式在變數宣告週期結束時被呼叫

3、解構函式被呼叫分兩種情況:堆疊中定義的物件、全域性區中定義的物件

證明1:

解構函式不能過載、不能有引數;

編譯不通過。

既然不能有引數,那過載更不可能了

證明成功。

證明2:

解構函式在變數宣告週期結束時被呼叫;

區域性變數的生命週期是在一個大括號內,即一個所處塊結束。

所以:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你呼叫了一次類別建構函式n");
	}
	~Test()
	{
		printf("你呼叫了一次類的解構函式n");
	}
};
int main()
{
	{
		Test te;
		printf("te生命週期即將結束。n");
	}                                    // 解構應該在這裡被呼叫
	printf("te生命週期結束。n");
	system("pause");
	return 0;
}

執行結果如下:

斷點

結果

證明成功。

證明3:

解構函式被呼叫分兩種情況:堆疊中定義的物件、全域性區中定義的物件;

已知堆疊中定義的物件(區域性變數)在塊語句結束之後就會被呼叫,那麼帶有return的main函數是在返回前呼叫解構,還是返回後呢?

程式碼如下:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你呼叫了一次類別建構函式n");
	}
	~Test()
	{
		printf("你呼叫了一次類的解構函式n");			// 斷點--組合
	}
};
int main()
{
	Test te;
	// system("pause");					// 不要使用pause,不然無法返回
	return 0;
}

斷點-偵錯-組合:

可以看到是在函數返回前被呼叫的。

如果在全域性區定義的物件呢?

這個問題很難說,像我一樣定義兩個斷點就行了,如下:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你呼叫了一次類別建構函式n");
	}
	~Test()                                    // 斷點
	{
		printf("你呼叫了一次類的解構函式n");			
	}
};
Test te;
int main()
{
	// system("pause");					// 不要使用pause,不然無法返回
	return 0;                           // 斷點
}

執行:

發現一執行就斷在了return,當我們發F10繼續執行的時候,並沒有直接呼叫解構,而是到了括號那裡:

繼續F10:

通過翻譯,可以得知這就是程序結束時的一些收尾工作。

繼續F10:

現在大概可以總結了,類的物件定義為全域性變數時,是在main函數結束之後程序退出之前,呼叫的解構函式。

小結

當類的物件定義為區域性變數時(堆疊),定義這個物件的塊作用域結束時就會呼叫該物件的解構函式,如果在main函數這個塊作用域中定義的物件,那麼就是在return之前呼叫解構。

當類的物件定義為全域性變數時(全域性區),會在main函數return函數返回之後和程序結束之前,呼叫該物件的解構函式。

解構函式的作用

我們知道了解構函式都是在類的物件生命週期結束時被呼叫,那麼就代表下面不會再使用到這個物件;所以解構函式一般用於一些收尾的工作,以防忘記。

比如當你使用了該物件的成員申請了記憶體(malloc、new等)、或者open了一些檔案,那麼可以在解構函式中free delete 或者close。

例如:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	int x;
	char* name;
	Test()
	{
		name = (char*)malloc(sizeof(char)*20);        // 構造時動態申請
	}
	~Test()
	{
		if(this->name!=0)                             // 解構時判斷是個否為空,不為空釋放
		{
			free(name);
			name = 0;
		}
	}
};
int main()
{
	Test te;
	return 0;
}

這裡我就不執行了,大家可以自己測試下。

總結

建構函式

1、和類具有相同名稱,並且沒有返回值型別的函數,就是類別建構函式

2、建構函式在定義物件的時候被呼叫

3、建構函式可以進行函數過載,可以有很多個

4、建立物件時預設呼叫的是無參構造

解構函式

1、類別建構函式名前加上'~'這個符號,就是類的解構函式

2、解構函式不能過載、不能有引數

3、解構函式在變數宣告週期結束時被呼叫

4、解構函式被呼叫分兩種情況:堆疊中定義的物件、全域性區中定義的物件

到此這篇關於C++類別的構造與解構特點及作用詳解的文章就介紹到這了,更多相關C++類別的構造與解構內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com