建構函式 解構函式 拷貝建構函式
一、建構函式
為了更好的說明建構函式,首先建立一個簡單的日期類
Date.cpp
class Date { public: void DatePrint(); void DateSet(int year, int month, int day); private: int m_year; int m_month; int m_day; }; void Date::DateSet(int year, int month, int day) { m_year = year; m_month = month; m_day = day; } void Date::DatePrint() { cout << m_year << "-" << m_month << "-" << m_day << endl; }
1.成員變數命名風格
看到一些程式碼我們可能看的一臉僵硬,例如:
void Date::DateSet(int year, int month, int day)
{
year = year;
month = month;
day = day;
}
這裡的 year, month, day 到底是成員變數呢,還是函式形參呢,所以在建立成員變數的時候,我們最好加上字首或字尾用來區分,例如:
void Date::DateSet(int year, int month, int day) { m_year = year; m_month = month; m_day = day; }
2. 概念
建構函式是一個特殊的成員函式,名字與類相同,建立型別物件時由編譯器自動呼叫,在類的生命週期內只調用一次
3. 特性
(1) 函式名與類名相同
(2) 無返回值
(3) 物件例項化時編譯器自動呼叫對應的建構函式
(4) 建構函式可以過載
4. 無參建構函式
如果類中沒有顯式定義的建構函式,C++編譯器會自動的生成一個無參的建構函式,使用者顯式定義,編譯器將不再生成,也許有人會疑問無參的建構函式看起來沒什麼用,編譯器為什麼要生建構函式呢?我們建立一個 Time 類,程式碼如下:
class Date { public: void DatePrint(); void DateSet(int year, int month, int day); private: // 內建型別 int m_year; int m_month; int m_day; // 自定義型別 Time m_t; }; class Time { public: Time(); private: int m_hour; int m_minute; int m_second; }; Time::Time() { cout << "Time()" << endl; m_hour = 10; m_minute = 14; m_second = 15; }
我們可以發現,對於上面的程式碼,編譯器生成的預設建構函式會對自定義型別成員 m_t 呼叫它的預設成員函式
另外,如果通過無參建構函式建立物件時,不用跟括號,否則就成了函式宣告,例如:
void DateTest()
{
Date d1;
Date d2();
}
d1 為呼叫無參建構函式,d2 為函式宣告,該函式無參,返回值為日期型別的物件
5. 帶參建構函式
Date::Date(int year , int month, int day)
{
m_year = year;
m_month = month;
m_day = day;
}
呼叫帶參構函式
void DateTest()
{
Date d3(2018, 11, 21);
}
二、解構函式
1. 概念
程式在物件在銷燬時會自動呼叫解構函式,完成類的一些資源清理工作
2. 特性
(1) 解構函式名是在類名前加上字元 ~
(2) 無引數無返回值
(3) 一個類有且只有一個解構函式,若未顯式定義,系統會自動生成預設的解構函式
(4) 物件生命週期結束時,C++編譯系統系統自動呼叫解構函式
(5) 解構函式不可以過載
3. 編譯器生成的預設解構函式對會自定型別成員呼叫它的解構函式
class String
{
public:
String(const char* str = "test");
~String();
private:
char* m_str;
};
String::String(const char* str)
{
m_str = (char*)malloc(strlen(str) + 1);
strcpy(m_str, str);
}
String::~String()
{
cout << "~String()" << endl;
free(m_str);
}
class Person
{
private:
String m_name;
int m_age;
};
4. 一個類中如果涉及到了資源的管理,解構函式一定要給出
三、拷貝建構函式
1. 概念
拷貝建構函式,它是由編譯器用來完成一些基於同一類的其他物件的構建及初始化。其唯一的引數(物件的引用)是不可變的(常用const型別)
2. 特性
(1) 拷貝建構函式是一種特殊的建構函式,是建構函式的一個過載形式
(2) 拷貝建構函式的引數只有一個且必須使用引用傳參,如果使用傳值方式傳遞,它將會引發無窮遞迴呼叫
(3) 若未顯示定義,系統生成預設拷貝建構函式,預設的拷貝建構函式物件按記憶體儲存按位元組序完成拷貝,這種拷貝我們叫做淺拷貝,或者值拷貝,這種拷貝只對物件中的資料成員進行簡單的賦值
來一段程式碼檢驗一下:
class Date
{
public:
Date(int year = 2018, int month = 11, int day = 23);
Date(const Date& d);
private:
int m_year;
int m_month;
int m_day;
};
Date::Date(int year, int month, int day)
{
m_year = year;
m_month = month;
m_day = day;
}
Date::Date(const Date& d)
{
m_year = d.m_year;
m_month = d.m_month;
m_day = d.m_day;
}
3. 預設拷貝建構函式
程式碼說明:d2呼叫預設拷貝構造,d2和d1的值一樣
#include <iostream>
using namespace std;
class Date
{
public:
Date(int year = 2018, int month = 11, int day = 23);
private:
int m_year;
int m_month;
int m_day;
};
Date::Date(int year, int month, int day)
{
m_year = year;
m_month = month;
m_day = day;
}
void Test()
{
Date d1;
Date d2(d1);
}
4. 一個類中如果涉及到了資源的管理,拷貝函式一定要顯式提供,否則會共用同一個空間,該空間被多次釋放,從而引起程式的崩潰,不信你看
class String
{
public:
String(const char* str = "word");
~String();
private:
char* _str;
};
String::String(const char* str)
{
_str = (char*)malloc(strlen(str) + 1);
strcpy(_str, str);
}
String::~String()
{
cout << "~String()" << endl;
free(_str);
}
void test()
{
String s1("hello");
String s2(s1);
}