C++中類的6個默認成員函數


這里寫圖片描述
1.構造函數
構造函數是一個特殊的成員函數,名字與類名相同,創建類類型對象時,由編譯器自動調用,在對象的生命周期內只且值調用一次,以保證每個數據成員都有一個合適的初始值。
【構造函數特性】
1、函數名與類名相同。
2、沒有返回值。
3、有初始化列表(可以不用)。
4、新對象被創建,由編譯器自動調用,且在對象的生命期內僅調用一次。
5、構造函數可以重載,實參決定了調用那個構造函數。
6、如果沒有顯示定義時,編譯器會提供一個默認的構造函數。
如果一個類中沒有定義任何的構造函數,那么編譯器只有在以下三種情況,才會提供默認的構造函數:
1、如果類有虛擬成員函數或者虛擬繼承父類(即有虛擬基類)時;
2、如果類的基類有構造函數(可以是用戶定義的構造函數,或編譯器提供的默認構造函數);
3、在類中的所有非靜態的對象數據成員,它們對應的類中有構造函數(可以是用戶定義的構造函數,或編譯器提供的默認構造函數)
7、無參構造函數和帶有缺省值得構造函數都認為是缺省構造函數,並且缺省構造函數只能有一個。
因為在調用是如果出現Date( ),編譯器並不知道該調用哪一個構造函數;

      Date( int year = 1990, int month = 1, int day = 1)
{
}
//
Date( )
{
}

8、構造函數不能用const來修飾,為什么呢?

【初始化列表】
初始化列表:以一個冒號開始,接着是一個以逗號分隔的數據成員列表,每個數據
成員后面跟一個放在園括號中的初始化式。

        Date(int year = 1990, int month = 1, int day = 1)
:_year(year)
, _month( month)
, _day( day)
{
}

常量,變量的引用,和沒有缺省初始化的類必須在初始化列表中初始化;
【初始化順序】
1、每個成員在初始化列表中只能出現一次。(為什么?)
2、初始化列表僅用於初始化數據成員,並不指定這些數據成員的初始化順序,
數據成員在類中定義順序就是在參數列表中的初始化順序。
3、盡量避免使用成員初始化成員,成員的初始化順序最好和成員的定義順序保持一致。
【默認構造函數】
類如果沒有顯式定義構造函數時,編譯器會合成一個默認的構造函數,該構造函數中什么工作都不做。只要顯式定義了,即使該構造函數什么也不做,編譯器也不會為該類合成默認的構造函數。編譯器生成的默認構造函數使用與變量初始化相同的規則來初始化成員,具有類類型的成員通過運行各自的默認構造函數來進行初始化。內置和符合類型的成員如指針、數組,只對定義在全局作用域中的對象初始化,當對象定義在局部作用域時,內置和符合類型的成員不進行初始化。在某些情況下,默認構造函數是由編譯器隱式使用的。

構造函數作用:
1、構建對象
2、初始化對象
3、類型轉換
【explcit】
用explicit修飾構造函數,抑制由構造函數定義的隱式轉換,erplicit關鍵字類內部的構建聲明上,在類的定義體外部的定義上不再重復。

例:Date類的構造函數:

class Date
{
public:
Date( int year = 1990, int month = 1, int day = 1)//帶默認值
:_year( year)//初始化列表
, _month( month)
, _day( day)
{

}

private:
int _year;
int _month;
int _day;
}

2.拷貝構造函數
只有單個形參,而且該形參是對本類類型對象的引用(常用const修飾),這樣的構造函數稱為拷貝構造函數。拷貝構造函數是特殊的構造函數,創建對象時使用已存在的同類對象來進行初始化,由編譯器自動調用。
Date(const Date & d)
{
_year = d ._year;
_month = d ._month;
_day = d ._day;
}
【特征】
1、它是構造函數的重載。
2、它的參數必須使用同類型對象的引用傳遞。(思考為什么?)

3、如果沒有顯式定義,系統會自動合成一個默認的拷貝構造函數。默認的拷貝構造函數會依次拷貝類的數據成員完成初始化。

【使用場景】
1、對象實例化對象
Date d1(1990, 1, 1);
Date d2(d1);

2、傳值方式作為函數的參數
void FunTest(const Date date)
{}

3、傳值方式作為函數返回值
Date FunTest()
{
Date date;
return date;
}
3.析構函數
析構函數:與構造函數功能相反,在對象被銷毀時,由編譯器自動調用,完成類的一些資源清理和汕尾工作;
【特性】
a、析構函數在類名(即構造函數名)加上字符~。
b、析構函數無參數無返回值。
c、一個類有且只有一個析構函數。若未顯示定義,系統會自動生成缺省的析構函數。
d、對象生命周期結束時,C++編譯系統系統自動調用析構函數。
e、注意析構函數體內並不是刪除對象,而是做一些清理工作。
f、 認識到析構函數體本身並不直接銷毀成員是非常重要的。成員是在析構函數體之后隱含的析構階段中被銷毀的。
【什么時候會調用析構函數】
無論何時,一個對象被銷毀,就會自動調用其析構函數:
a.變量離開其作用域是被銷毀;
b.當一個對象的銷毀時,其成員被銷毀;
c.容器(無論是標准庫容器還是數組)被銷毀時,其元素被銷毀;
d.對於動態分配的對象,當指向它的指針用delete運算符被銷毀;
e.對於臨時對象,當創建它的完整表達式結束時被銷毀。
【 warning】
當指向一個對象的引用或指針離開作用域時,析構函數不會執行。
4.賦值操作符重載;
5.取地址操作符重載;
6.const修飾的取地址操作符重載;
【操作符重載】

重載操作符是具有特殊函數名的函數,關鍵字operator后面接需要定義的操作符符號。
操作符重載也是一個函數,具有返回值和形參表。它的形參數目與操作符的操作數目相同,
函數調用操作符可以接受任意數目的操作數。
返回類型 operate 操作符(參數列表);

注意:
1、不能通過連接其他符號來創建新的操作符:比如operator@;
void operator @(){}

2、重載操作符必須有一個類類型或者枚舉類型的操作數
int operator +(const int _iNum1 , const int _iNum2 ) // 報錯
{
return ( _iNum1 + _iNum2);
}

typedef enum TEST {one ,two ,three };
int operator+(const int _iNum1 , const TEST _test )
{
return _iNum1;
}

3、用於內置類型的操作符,其含義不能改變,例如:內置的整型+,不能改變其含義

5、不在具備短求職特性
重載操作符不能保證操作符的求職順序,在重載&&和||中,對每個操作數
都要進行求值,而且對操作數的求職順序不能做規定,因此:重載&&、
||和逗號操作符不是好的做法。

6、作為類成員的重載函數,其形參看起來比操作數數目少1
成員函數的操作符有一個默認的形參this,限定為第一個形參。
CTest operator+(const CTest test1, const CTest test2)const // 報錯
{
return test1;
}

CTest operator+(const CTest test1)const
{
return test1;
}

7、一般將算術操作符定義為非成員函數,將賦值運算符定義成員函數
8、操作符定義為非類的成員函數時,一般將其定義為類的友元函數
9、== 和 != 操作符一般要成對重載
10、下標操作符[]:一個非const成員並返回引用,一個是const成員並返回引用
11、解引用操作符*和->操作符,不顯示任何參數
13、自增自減操作符
前置式++/–必須返回被增量或者減量的引用
后綴式操作符必須返回舊值,並且應該是值返回而不是引用返回
14、輸入操作符>>和輸出操作符<<必須定義為類的友元函數
【建議】
使用重載操作符,可以令程序更自然、更直觀,而濫用操作符重載會使得類難以理解,在實踐中很少發生明顯的操作符重載濫用。但有些程序員會定義operator+來執行減法操作,當一個重載操作符不明確時,給操作符取一個名字更好,對於很少用的操作,使用命名函數通常比用操作符好,如果不是普通操作,沒有必要為簡潔而用操作符。

賦值操作符重載;(以Date類為例)
Date& operator=(const Date& d)//定義為類的成員函數
{
_year = d._year;
_month = d._month;
_day = d._day;
return *this ;
}
取地址操作符重載和const修飾的取地址操作符重載; ;
class CTest
{
public:
CTest* operator&()
{
return this ;
}

     const CTest* operator &()const
{
return this ;
}

};


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com