本章節包括:類、複製控制以及重載操作符與轉換。
12、類
在C++中,用類來定義自己的抽象資料類型,通過定義類型來對應所要解決的問題中的各種概念,可以使我們更容易編寫、調試和修改程式。
1、類的定義:(1)類可以沒有成員,也可以定義多個成員,成員可以是資料、函數或類型別名;(2) 建立一個類類型的對象時,編譯器會自動使用一個建構函式來初始化該對象,建構函式一般應使用一個建構函式初始化列表來初始化對象的資料成員;(3) 成員函數,在類內部,聲明成員函數時必需的,而定義成員函數則是可選的,在類內部定義的函數預設為inline.
class Sales_item{<br />public:<br /> //預設建構函式需要初始化對象的資料成員<br /> Sales_item():units_sold(0),revenue(0.0){}<br /> double avg_price() const;//先聲明成員函數<br />private:<br /> ...<br />};//分號很重要<br />double Sales_items::avg_price() const//在類外定義成員函數<br />{<br /> ...<br />}
2、資料抽象是一種依賴於介面和實現分離的編程技術。封裝是一項將低層次的元素組合起來形成新的、高層次實體的技術。資料抽象和封裝提供了兩個重要優點:(1)避免類內部出現無意的、可能破壞對象狀態的使用者級錯誤;(2)隨時間推移可以根據需求改變或缺陷報告來完善類實現,而無須改變使用者級代碼。
3、顯式指定inline成員函數:在類內部定義的成員函數,將自動作為inline處理,同時也可以顯式的將成員函式宣告為inline,可以在類定義體內部指定一個成員為inline作為其聲明的一部分,或者也可以在類定義體外部的函數定義上指定inline.在聲明和定義處指定inline都是合法的。
class Screen{<br />public:<br /> char get() const{return contents[cursor];}//自動作為inline處理<br /> inline char get(index ht,index wd) const;//類定義體內部指定一個成員為inline<br /> index get_cursor() const;<br />}<br />inline Screen::index Screen::get_cursor() const//類定義體外部的函數定義上指定inline<br />{<br /> return cursor;<br />}
4、類的成員函數具有一個附加的隱含形參,即指向該類對象的一個指標,這個隱含形參命名為this,與調用成員函數的對象綁定在一起。成員函數不能定義this形參,而是由編譯器隱含的定義。當我們需要將一個對象作為整體引用而不是引用對象的一個成員時,必須使用this指標。
class Screen{<br />public:<br /> Screen& move(index r,index c);<br />};</p><p>Screen& Screen::move(index r,index c)<br />{<br /> index row=r*width;<br /> cursor=row+c;<br /> return *this;<br />}
5、在普通的非const成員函數中,this的類型是一個指向類類型的const指標,可以改變this所指向的值,但是不能改變this所儲存的地址,在const成員函數中,this的類型是一個指向const類類型對象的const指標。既不能改變this所指向的對象,也不能改變this所儲存的地址。
6、有時我們希望類的資料成員可以修改,這可以通過將它們聲明為mutable來實現。儘管do_display是const,它也可以增加access_ctr,該成員是可變成員,所以任意成員函數,包括const函數,都可以改變access_ctr的值。
class Screen{<br />public:<br />private:<br /> mutable size_t access_ctr;<br />};</p><p>void Screen::do_display(std::ostream& os) const<br />{<br /> ++access_ctr;<br /> os<<contents;<br />}
13、複製控制
每種類型,無論是內建類型還是類類型,都對該類型對象的一組操作的含義進行了定義。每種類型還定義了建立該類型的對象時會發生什麼——建構函式定義了該類類型對象的初始化。類型還能控制複製、賦值或者撤銷該類型的對象時會發生什麼——類通過特殊的成員函數:複製建構函式、賦值操作符和解構函式來控制這些行為。
(1) 複製建構函式是一種特殊建構函式,具有單個形參,該形參是對該類類型的引用,當定義一個新對象並用一個同類型的對象對它進行初始化時,將顯式使用複製建構函式。當將該類型的對象傳遞給函數或從函數返回該類型的對象時,將隱式使用複製建構函式。
(2) 解構函式是建構函式的互補,當對象超出範圍或動態分配的對象被刪除時,將自動應用解構函式。
(3) 賦值操作符與建構函式一樣,可以通過指定不同類型的右運算元而重載。
複製建構函式、賦值操作符和解構函式總稱為複製控制。
1、智能指標就是將一個計算機與類指向的對象相關聯。使用計數跟蹤該類有多少個對象共用同一指標。使用計數為0時,刪除對象。
14、重載操作符與轉換
C++允許我們重定義操作符用於類類型對象時的含義,如果需要,可以像內建轉換那樣使用類類型轉換,將一個類型的對象隱式轉換到另一個類型。通過操作符重載,程式員能夠針對類類型的運算元定義不同的操作符版本。
1、不能重載的操作符有如下:::、.*、.、?:。通過串連其它合法符號可以建立新的操作符,比如定義一個operator **以提供求冪運算是合法的。
2、重載操作符必須具有一個類類型操作符,用於內建類型的操作符,其含義不能改變,比如,內建的整型加好符號符不能重定義:
int operator+(int,int);//Error:
3、重載一元操作符如果作為成員函數就沒有形參,如果作為非成員函數就有一個形參。類似的作為類成員的重載函數,其形參看起來比運算元少1.一般情況,將算術和關係操作符定義為非成員函數,而將賦值操作符定義為成員函數。
Sales_item& Sales_item::operator+=(const Sales_items&);<br />Sale_items operator+(const Sales_item&,const Sales_item&);
4、操作符定義為非成員函數時,通常必須將它們設定為所操作類的友元。
class Sales_item{<br /> friend std::istream& operator>>(std::istream&,Sales_item&);<br /> friend std::ostream& operator<<(std::ostream&,const Sales_item&);<br />public:<br /> Sales_item& operator+=(const Sales_item&);<br />};
5、輸出操作符<<的重載:為了與IO標準庫一致,操作符應接受ostream&作為第一個形參,對類類型const對象的引用作為第二個形參,並返回對ostream形參的引用。而且IO操作符必須為非成員函數。
ostream& operator<<(ostream& os,const ClassType &object)<br />{<br /> os<<...<br /> return os;<br />}
6、輸入操作符>>的重載:與輸出操作符類似,區別在於輸入操作符必須處理錯誤和檔案結束的可能性。
7、標準庫定義的函數對象,標準庫定義了一組算術、關係與邏輯函數對象類,同時標準庫還定義了一組函數適配器,使我們能夠特化或者擴充標準庫所定義的以及自訂的函數對象類,這些標準庫函數物件類型是在functional標頭檔中定義的。
plus<int> intAdd;<br />negate<int> intNegate;<br />int sum=intAdd(10,20);//sum=30<br />sum=intAdd(10,intNegate(10));//sum=0
8、函數對象的函數適配器:
(1) 綁定器:它通過將一個運算元綁定到給定值而將二元函數對象轉換為一元函數對象
(2) 求反器:它將謂詞函數對象的真值求反。
count_if(vec.begin(),vec.end(),bind2nd(less_equal<int>(),10));</p><p>count_if(vec.begin(),vec.end(),not1(bind2nd(less_equal<int>(),10)));</p><p>
9、轉換操作符是一種特殊的類成員函數,它定義將類類型轉變為其它類型值的轉換。轉換操作符在類定義體內聲明,在保留字operator之後跟著轉換的目標類型,注意:必須是成員函數,不能指定傳回型別,並且形參表必須為空白
class SmallInt{<br />public:<br /> SmallInt(int i=0):val(i)<br /> {<br /> if(i<0||i>255)<br /> throw std::out_of_range("Bad SmallInt...");<br /> }<br /> operator int() const{return val;}<br />private:<br /> std::size_t val;<br />};