類的默認成員函數
類的組成包括數據成員與成員函數。
在類中一共有有六個默認成員函數,
- 構造函數
- 拷貝構造函數
- 析構函數
- 賦值操作符重載
- 取地址操作符重載
- const修飾的取地址操作符重載
利用一個實例(日期類)進行舉例
先是定義一個日期類
class Date
{
public:
void show();
private:
int _year;
int _month;
int _day;
};
這就是一個簡單的類定義。下面依次介紹各個默認成員函數
一.構造函數
因爲在類中,數據是私有的,只能在類內進行訪問操作,所以初始化這些數據也就只能在類進行,需要定義一個公有函數,這就是構造函數。這個函數只有在定義對象時對其初始化使用一次。
Date();
- 構造函數的函數沒有返回值。
- 構造函數的名字一定是與類名相同的。
- 構造函數可以重載,可以是有參的,無參的
- 在進行類的實例化的時候,就會自動調用構造函數,若是沒有定義就會調用系統自動生成的構造函數,若是有人爲定義,則會根據其參數進行選擇對應的構造函數及其重載函數。
- 構造函數可以其他成員函數相同,也可以在類外進行定義,在類內聲明。
- 無參的構造函數與全缺省的構造函數都認爲是缺省構造函數,並且缺省的構造函數只能有一個
//無參的構造函數
Date()
{
_year=1900;
_month=1;
_day=1;
}
//全缺省的構造函數
Date(int year=1900, int month=1, int month=1)
{
_year=year;
_month=month;
_day=day;
}
int main()
{
Date d1;
//Date d2;
}
由於上述兩種函數的調用方式相同,都是不需要傳參的,所以如果一個類中既有無參的構造函數又有全缺省的構造函數,就會出現錯誤,不知道當前應該調用哪個構造函數來進行初始化。所以在類的定義中不可以同時出現這兩種構造函數。
二.拷貝構造函數
拷貝構造函數是創建隊形在初始化時用同類的對象進行初始化。也是一種構造函數。
//拷貝構造函數:
Date(const Date& d)
{
_year=d._year;
_month=d._month;
_day=d._day;
}
int main()
{
Date d1(2018,3,20);
Date d2(d1);
Date d3=d2; // 這樣也算是拷貝構造函數
}
- 拷貝構造函數是構造函數的重載
- 拷貝構造函數的參數必須使用引用傳參,若使用傳值傳參則會引起無限的遞歸調用。在調用這個函數時,會傳進來一個實參,形參用於接收,所以在這個函數的棧幀中會形成一個臨時變量,用於儲存實參的值,這裏的這個空間需要用拷貝構造函數初始化,所以此時就需要遞歸調用拷貝構造函數,調用拷貝函數又會需要形成臨時變量,所以就會一直遞歸調用,就無法出來。造成了無窮遞歸的現象。
- 若在類中沒有定義,則系統會默認缺省的拷貝構造函數,就會依次拷貝類成員進行初始化。
三.析構函數
當一個對象的生命週期結束時,c++編譯系統會自動調用一個成員函數,就是析構函數。
1. 析構函數的函數名是在類名前加~
2. 析構函數沒有參數也沒有返回值
3. 一個類中就只有一個析構函數,不支持重載,若沒有定義,則系統會默認生成。
4. 析構函數的作用是清理空間,若在創建對象時,有malloc出來的空間,將他們銷燬。析構函數並不是刪除對象,對象是在生命週期結束後會有操作系統將其收回。不需要人爲收回。
class Test
{
pubilc:
Test(int size)
{
ptr=(int *)malloc(size * sizeof(int))
}
~Test()
{
if(ptr)
{
free(ptr);
ptr=0;
}
}
private:
int *ptr;
}
析構函數的調用順序與構造函數相反。先定義的函數先調用其構造函數,後調用析構函數。
四.運算符重載
運算符重載是爲了增加程序的可讀性。因爲沒有經過重載的運算符是不能運算自定義類型的,例如日期的加減,就不能單純的只用未重載的運算符進行計算。需要根據不同情況自己定義。
運算符重載的特徵:
operator+運算符 構成函數名
重載運算符以後,不能改變運算符的優先級/結合性/操作數個數
//運算符小於的重載
bool operator<(const Date& d)
{
//自定義函數內部。
}
c++中不可以重載的運算符
1. .*
2. sizof
3. ::
4. ? :
5. .
賦值運算符的重載
首先需要說明一下賦值運算符與拷貝構造函數的區別
拷貝構造函數是在創建對象時使用的,用一個已有對象初始化這個剛創建的對象。而賦值是給一個已經創建好的對象進行拷貝賦值。
函數名是operator+運算符,爲了可讀性更高,編譯系統會在碰見重載的運算符時,檢查運算符的操作數是否爲自定義類型,若是自定義類型,就轉到運算符重載函數。進行函數內部操作。
bool operator=(const Date& d)
{
return _year=d._year;
&& _month=d._month;
&& _day=d._day;
}
在這裏是只需要傳一個參數。還有一個是隱含的this指針,所以上述代碼就可以等價於
bool operator=(Date *this,const Date& d)
{
return this->_year=d._year;
&& this->_month=d._month;
&& this->_day=d._day;
}