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();
}
複製程式碼
解構函式
解構函式存在的必要性:
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();
}
複製程式碼
當物件要被系統釋放時,解構函式被呼叫,在解構函式中可以做一些善後處理處理的工作,如釋放記憶體。
拷貝建構函式
概念:用一個已有的物件來初始化一個被建立的同類物件,是一種特殊的成員函式。
宣告的一般格式: 類名(類名 & 物件名);
利用拷貝建構函式可以實現同類物件的資料傳遞, 即物件的“克隆”。(注意:與物件賦值的不同) (相對於拷貝建構函式,前面介紹的建構函式被稱為普通建構函式)
拷貝建構函式的性質 :
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();
}
複製程式碼
淺拷貝(值拷貝)問題
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();
}
複製程式碼
以上就是因為淺拷貝導致中止。錯誤的原因:兩個物件的指標指向同一儲存地址,析構時要求釋放兩次。
解決問題的方法:深拷貝
在拷貝建構函式中,顯式地為每個拷貝物件申請資料,這種拷貝構造方式稱為深拷貝。
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();
}
複製程式碼