構造和析構
構造函數
定義
: C++中的類可以定義與類名相同的特殊成員函數,這種與類名相同的成員函數叫做構造函數。
“`c++
class 類名{
類名(形參){
構造體
}
}
* 比如:
class A
{
A(形參)
{
}
}
#define _CRT_SECURE_NO_WARNING
#include "stdafx.h"
using namespace std;
class Test
{
public:
Test(int x, int y) //Test類的構造函數,作用:在對象被創建時用來初始化對象的函數(函數可以被重載)
{
m_x = x;
m_y = y;
}
void Print_Point()
{
cout << "x = " << m_x << " ,y = " << m_y << endl;
}
private:
int m_x;
int m_y;
};
int main()
{
Test T1(1, 2);
T1.Print_Point();
return 0;
}
析構函數
~Test(); //析構函數沒有形參,不能被重載
注意
:析構函數和構造函數都沒有返回值。
什麼時候用到析構函數呢?當對象T1是被在其他函數中使用的,那麼執行完函數後T1被銷燬前會觸發析構函數。
如果自己不在類中寫構造函數,那麼編譯器在編譯的時候就會默認構造無參構造函數。(其實就是一個空函數Test();)
析構函數調用的順序,跟構造相反,誰先構造的,誰後析構
拷貝構造函數
當我們需要用屬於相同的類下的一個對象去初始化另一個對象時,需要用到拷貝函數。
比如在Test類中有如下一個拷貝函數,沒有則系統默認:
Test(const Test &another) //注意這裏的&anoher表示引用
{
m_x = another.m_x;
m_y = another.m_y;
}
則在主函數中寫以下語句可以實現用一個已初始化的對象去未初始化的對象。
Test t1(1,2);
Test T1(t1); //可以通過t1給T1賦值,與Test T1 = t1;等價
深拷貝和淺拷貝
在main函數中要實現一個對象向另一個對象實現拷貝,往往用以下語句:
int main()
{
Teacher t1(1, "zhang3");
Teacher t2(t1);
return 0;
}
如果在類的定義中沒有定義一個深拷貝函數,則編譯器自動執行的將是淺拷貝函數,那麼程序在執行時就會發生崩潰,原因如下:
* 編譯器默認執行的淺拷貝函數:
Teacher(const Teacher &another)
{
m_id = another.m_id;
m_name = another.m_name; //將t1的成員拷貝給t2時,t2的指針*name將指向t1的*name所指向的堆區空間
}
那麼當執行完淺拷貝後,將析構函數,即釋放掉t2中的*name所指向的堆區空間,所以t1中*name所指向的空間也不存在了,那麼當析構t1時,程序就會報錯。所以要使用深拷貝函數:
Teacher(const Teacher &another) //實現深拷貝
{
m_name = (char*)malloc(sizeof(another.m_name));
strcpy(m_name, another.m_name);
m_id = another.m_id;
}
完整程序如下:
#include "stdafx.h"
using namespace std;
class Teacher
{
public:
Teacher(int id, char *name)
{
m_id = id;
m_name = (char*)malloc(sizeof(name));
strcpy(m_name, name);
}
void PrintT()
{
cout << "m_id = " << m_id << ", m_name = " << m_name << endl;
}
Teacher(const Teacher &another) //實現深拷貝
{
m_name = (char*)malloc(sizeof(another.m_name));
strcpy(m_name, another.m_name);
m_id = another.m_id;
}
~Teacher()
{
cout << "~Teacher()...." << endl;
}
private:
int m_id;
char *m_name;
};
int main()
{
Teacher t1(1, "zhang3");
t1.PrintT();
Teacher t2(t1);
t2.PrintT();
return 0;
}
編譯結果如下:
構造函數的初始化列表
一個類的成員中有其他類的對象,那麼要初始化這個對象,必須得把它寫到初始化列表中。
class B
{
public:
B(A &a1,A &a2,int b):m_a1(a1),m_a2(a2)
{
m_b = b;
}
private:
int m_b;
A m_a1;
A m_a2;
}