C++複製控制:賦值操作符和解構函式

QingLiXueShi發表於2015-02-21

一、賦值操作符

類定義了該型別物件賦值時會發生什麼。與拷貝建構函式一樣,如果類沒有定義自己的賦值操作符,編譯器會合成一個。

1、過載操作符的簡單介紹

過載操作符是一些函式,其名字為operator後跟著所定義的操作符的符號,通過定義名為operator=的函式,我們可以對賦值進行定義。操作符函式的形參表必須具有與該運算元數目相同的形參(如果操作符是一個成員,則包括隱式this形參)。賦值是二元操作符,對應的兩個形參,第一個形參為左運算元,第二個形參為右運算元。

注意:

(1)當操作符為成員函式時,它的第一個運算元隱式繫結到this指標。

(2)有些操作符,例如賦值操作符必須定義為成員函式,因此賦值操作符可接受單個形參。

(3)賦值操作符返回對右運算元的引用。

 

2、合成賦值操作符

合成賦值操作符會執行逐個成員賦值:右運算元物件的每個成員賦值為左運算元物件的對應成員。對於陣列,給每個陣列元素賦值。

Sales_item& Sales_item::Sales_item(const Sales_item &rhs)
{
    isbn = rhs.isbn;
    units_sold = rhs.units_sold;
    revenue = rhs.revenue;
    return *this;                //返回對左運算元的引用
}

 

3、拷貝和賦值常一起使用

可以使用拷貝建構函式的類通常也可使用合成賦值操作符。一般而言,如果類需要拷貝建構函式,它也會需要賦值操作符。應將兩者看作一個單元,如果需要其中一個,我們幾乎也肯定需要另一個。

 

二、解構函式

解構函式的作用是完成所需資源的回收,作為類建構函式的補充。

1、何時呼叫解構函式

撤銷類物件時自動呼叫解構函式:

(1)變數在超出作用域時自動撤銷。例如:變數item遇到右}時。

(2)動態分配的物件只有在指向該物件的指標被刪除時才撤銷。例如:指標p。

Sales_item *p = new Sales_item;
{
    Sales_item item(*p);
    delete p;
}

注意:當物件的引用或指標超出作用域時,不會執行解構函式。只有刪除指向動態分配物件的指標或實際物件(而不是物件的引用)超出作用域時,才會執行解構函式。

(3)撤銷一個容器(不管是標準庫還是內建陣列)也會執行容器中元素的解構函式。

容器中的元素總是按逆序撤銷,首先撤銷下標為size()-1的元素,最後撤銷下標為0的元素。

{
    Sales_item *p = new Sales_item[10];
    vector<Sales_item> vec(p, p + 10);
    delete [] p;
}

 

2、何時編寫顯式解構函式

許多類不需要顯式解構函式,具有建構函式的類不一定需要定義自己的解構函式,僅在有些工作需要解構函式完成時,才需要解構函式。解構函式通常用於釋放在建構函式或在物件生命期內獲取的資源。

注意:

(1)如果類需要解構函式,則它也需要賦值操作符和拷貝建構函式,這是一個有用的經驗法則。

(2)解構函式並不僅限於用來釋放資源。一般而言,解構函式可以執行任意操作,該操作是類設計者希望在該類物件的使用完畢之後執行的。

 

3、合成解構函式

與拷貝建構函式和賦值操作符不同,編譯器總會為我們合成一個解構函式。合成解構函式按物件建立時的逆序撤銷每個非static成員,按成員在類中宣告的逆序撤銷成員。對於類型別的每個成員,合成解構函式呼叫該成員的解構函式撤銷物件。

注意:撤銷內建型別成員或複合型別成員沒什麼影響,合成解構函式並不刪除指標成員做指向的物件。

 

4、編寫解構函式

解構函式的名字前加~,沒有返回值,沒有形參(所以不能過載解構函式)。

注意:

(1)類可以定義多個建構函式,但只能提供一個解構函式,應用於類的所有物件。

(2)解構函式區別於拷貝建構函式和賦值操作符,即使定義了自己的解構函式,合成解構函式仍然執行。

class Sales_item
{
public:
    ~Sales_item(){}
private:
    string isbn;
    int units_sold;
    double revenue;
};

撤銷Sales_item物件時,首先執行這個什麼都不做的解構函式,然後再執行合成解構函式撤銷類的成員。

相關文章