C++ 建構函式和解構函式

ZhiboZhao發表於2021-06-29

C++是物件導向的程式語言呢,具有類class,類的初始化就需要呼叫類的建構函式,預設呼叫類的無參建構函式,如果重寫了類的建構函式,會覆蓋類的預設建構函式。

建構函式

建構函式是一種特殊的成員函式,除具有一般成員函式的特性外,還具有如下特殊性質:

1)、建構函式的函式名必須與其類名相同;

2)、不包含任何返回型別,也不能寫成void型別;

3)、一個類可以有多個建構函式(即建構函式過載),也可以沒有建構函式(在這種情況下,系統會自動為類建立一個預設建構函式,該建構函式無引數4) 、建構函式可以有引數,也可以沒有引數;);

4)、在建立物件時,系統會自動呼叫建構函式(例:執行 Person abc; 語句時就自動呼叫了建構函式),且只呼叫一次;

5)、用new運算子動態建立物件時也會自動呼叫建構函式;

6)、通常,設為public型別。

class Student
{
public:
	void mprintf(){
		cout << "name:" << name << "--------" << "age:" << age << endl;
	}
	//覆蓋該類的預設建構函式
	Student(char*name, int age){
		this->name = name;
		this->age = age;
	}

private:
	char* name;
	int age;

};

void main(){

	Student s("xiaoMing",15);
	s.mprintf();

	getchar();
}
複製程式碼

C++.png

解構函式

解構函式存在的必要性:

a)、如果建構函式中使用了new 命令申請了堆空間,在物件撤消時,就要用delete命令歸還物件所佔空間。否則,造成記憶體洩漏。

b)、退出程式時,進行檔案內容檢查,提示存檔操作 。
複製程式碼

解構函式是一種特殊的成員函式,除具有一般成員函式的特性外,還具有如下特性:

1)、解構函式的函式名必須與其類名相同,不能指定返回型別,也不能使用void。為了能與建構函式相區別,要在函式名前加~(波浪符);

2)、解構函式沒有引數,一個類中只能擁有一個解構函式,所以解構函式不能過載。定義格式為: ~類名(){ 函式體 } ;

3)、如果程式設計師沒有定義類的解構函式,系統會自動為類建立一個預設解構函式,形式為: ~類名(){ };

4)、通常為public型別,系統在撤消物件時,自動呼叫解構函式。也允許顯式呼叫;

5)、用delete運算子刪除物件時也會自動呼叫解構函式 。

class Student
{
public:
	void mprintf(){
		cout << "name:" << name << "--------" << "age:" << age << endl;
	}
	//覆蓋該類的預設建構函式
	Student(char*name, int age){
		this->name = name;
		this->age = age;
		cout << "建構函式" << endl;
	}
	//解構函式
	~Student(){
		cout << "解構函式" << endl;
	}

private:
	char* name;
	int age;

};

void func(){
	Student s("xiaoMing", 15);
	s.mprintf();
}

void main(){

	func();

	getchar();
}
複製程式碼

C++.png

當物件要被系統釋放時,解構函式被呼叫,在解構函式中可以做一些善後處理處理的工作,如釋放記憶體。

拷貝建構函式

概念:用一個已有的物件來初始化一個被建立的同類物件,是一種特殊的成員函式。

宣告的一般格式: 類名(類名 & 物件名);

利用拷貝建構函式可以實現同類物件的資料傳遞, 即物件的“克隆”。(注意:與物件賦值的不同) (相對於拷貝建構函式,前面介紹的建構函式被稱為普通建構函式)

拷貝建構函式的性質 :

1)、函式名必須與類名相同,並且不指定返回型別;

2)、只有一個引數,是同類的物件的引用;

3)、每一個類中都必須有一個拷貝建構函式。如果類中沒有宣告拷貝建構函式,編譯器就會自動生成一個具有上述形式的公有的拷貝建構函式。

拷貝建構函式被呼叫的場景:

1)、宣告時賦值 Student s1 = s;

2)、作為引數傳入,實參給形參賦值 func(s);

3)、作為函式返回值返回,給變數初始化賦值 Student s1 = func(s);

淺拷貝和深拷貝

如果在類的定義裡沒有提供拷貝建構函式,C++會提供一個預設的拷貝建構函式; 預設拷貝建構函式的拷貝方式是各成員逐一複製,這稱為是淺拷貝; 在某些情況下,淺拷貝會產生問題,例如:當一個類在它的建構函式動態分配了記憶體資源,淺拷貝只會複製該資源的地址,而不會為新建的物件重新分配一個資源,因此,會出現多個物件指向同一個堆空間的地址的現象。

淺拷貝也就是值拷貝:

class Student
{
public:
	void mprintf(){
		cout << "name:" << name << "--------" << "age:" << age << endl;
	}
	//覆蓋該類的預設建構函式
	Student(char*name, int age){
		this->name = name;
		this->age = age;
		cout << "建構函式" << endl;
	}
	//預設拷貝建構函式,就是值拷貝
	Student(const Student &obj){
		this->name = obj.name;
		this->age = obj.age;
		cout << "拷貝建構函式" << endl;
	}
	//解構函式
	~Student(){
		cout << "解構函式" << endl;
	}

private:
	char* name;
	int age;

};

void func(Student s){
	s.mprintf();
}

void main(){
	Student s("xiaoMing", 15);
	func(s);

	getchar();
}
複製程式碼

C++.png

淺拷貝(值拷貝)問題

class Student
{
public:
	void mprintf(){
		cout << "name:" << name << "--------" << "age:" << age << endl;
	}
	//覆蓋該類的預設建構函式
	Student(char*name, int age){
		this->name = (char*)malloc(100);
		strcpy(this->name, name);
		this->age = age;
		cout << "建構函式" << endl;
	}
	////預設拷貝建構函式,就是值拷貝
	//Student(const Student &obj){
	//	this->name = obj.name;
	//	this->age = obj.age;
	//	cout << "拷貝建構函式" << endl;
	//}
	//解構函式
	~Student(){
		cout << "解構函式" << endl;
		free(this->name);
	}

private:
	char* name;
	int age;

};

void func(){
	Student s("xiaoMing", 15);
	Student s1 = s;
	s1.mprintf();
}

void main(){
	
	func();
	
	getchar();
}

複製程式碼

C++.png

以上就是因為淺拷貝導致中止。錯誤的原因:兩個物件的指標指向同一儲存地址,析構時要求釋放兩次。

解決問題的方法:深拷貝

在拷貝建構函式中,顯式地為每個拷貝物件申請資料,這種拷貝構造方式稱為深拷貝。

class Student
{
public:
	void mprintf(){
		cout << "name:" << name << "--------" << "age:" << age << endl;
	}
	//覆蓋該類的預設建構函式
	Student(char*name, int age){
		this->name = (char*)malloc(100);
		strcpy(this->name, name);
		this->age = age;
		cout << "建構函式" << endl;
	}
   //深拷貝
	Student(const Student &obj){
		//複製name屬性
		int len = strlen(obj.name);
		this->name = (char*)malloc(len + 1);
		strcpy(this->name, obj.name);
		this->age = obj.age;
		cout << "拷貝建構函式" << endl;
	}
	//解構函式
	~Student(){
		cout << "解構函式" << endl;
		free(this->name);
	}

private:
	char* name;
	int age;

};

void func(){
	Student s("xiaoMing", 15);
	Student s1 = s;
	s1.mprintf();
}

void main(){
	
	func();
	
	getchar();
}
複製程式碼

C++.png

相關文章