一、賦值操作符
類定義了該型別物件賦值時會發生什麼。與拷貝建構函式一樣,如果類沒有定義自己的賦值操作符,編譯器會合成一個。
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物件時,首先執行這個什麼都不做的解構函式,然後再執行合成解構函式撤銷類的成員。