C++ 類
類的基本思想是數(shù)據(jù)抽象和封裝。
數(shù)據(jù)抽象是一種依賴于接口和實(shí)現(xiàn)分離的編程技術(shù),類的接口包括用戶所能執(zhí)行的操作;類的實(shí)現(xiàn)包括類的數(shù)據(jù)成員、負(fù)責(zé)接口實(shí)現(xiàn)的函數(shù)體以及定義類所需要的各種私有函數(shù)。
封裝實(shí)現(xiàn)了類的接口和實(shí)現(xiàn)的分離,封裝后的類隱藏了它的實(shí)現(xiàn)細(xì)節(jié),類的用戶只能使用接口而無法訪問實(shí)現(xiàn)部分。
類要想實(shí)現(xiàn)數(shù)據(jù)抽象和封裝,需要首先定義一個抽象數(shù)據(jù)類型。
一般來說類的設(shè)計(jì)者考慮類的實(shí)現(xiàn)過程,而類的程序員則只需要抽象的思考類做了什么,無需真正了解如何實(shí)現(xiàn)。
設(shè)計(jì)Sales_data類
我們將在后面學(xué)習(xí)如何自定義運(yùn)算符,現(xiàn)在我們只定義普通函數(shù)形式。
我們假設(shè)Sales_data的接口應(yīng)該包含以下操作
1一個isbn成員函數(shù),用于返回對象的ISBN編號
2一個名為combine成員函數(shù),用于將一個Sales_data對象的加法
3一個名為add的函數(shù),執(zhí)行將兩個Sales_data對象的加法
4一個read函數(shù),將數(shù)據(jù)從istream讀入到Sales_data對象中
5一個print函數(shù),將Sales_data對象的值輸出到ostream
使用Sales_data類
對于大部分人來說,我們只需要知道如何使用別人提供的接口。
此函數(shù)用來實(shí)現(xiàn)上述說明的五條操作的接口。
定義Sales_data類
我們定義bookNo(string)、units_sold(unsigned)、revenue(double),分別表示ISBN編號、書的銷量、書的總收入。
如前面所說,我們類包含兩個成員函數(shù),combine和isbn,此外我們還賦予Sales_data另一個成員函數(shù)用于返回書的平均價格,命名為avg_price,因?yàn)閍vg_price并非通用,所以它屬于類的實(shí)現(xiàn)的一部分,而不是接口的一部分。
定義和聲明成員函數(shù)的方式和普通函數(shù)一樣,成員函數(shù)的聲明必須在類的內(nèi)部,定義內(nèi)外沒有要求,作為接口組成部分的非成員函數(shù)(add,read,print)他們的定義和聲明都在類的外部。
注意:定義在類內(nèi)部的函數(shù)是隱式的內(nèi)聯(lián)(inline)函數(shù)
定義成員函數(shù)
盡管所有成員都必須在類的內(nèi)部聲明,但是成員函數(shù)體的定義不限制內(nèi)外,我們的函數(shù)isbn定義在類內(nèi),combine和avg_price定義在了類外。
我們先介紹isbn函數(shù),它的參數(shù)列表為空返回一個string對象,用于返回bookNo數(shù)據(jù)成員。
引入this
對于isbn成員函數(shù)的調(diào)用,我們會使用點(diǎn)運(yùn)算符,來訪問Sales_data類型的對象的isbn成員。后面我們將介紹一種例外的形式,當(dāng)我們調(diào)用成員函數(shù)時,實(shí)際上是替某個對象調(diào)用它,如果isbn指向bookNo,則他隱式的指向調(diào)用該函數(shù)的對象的成員,所以實(shí)際上他隱式的返回Sales_data對象的bookNo(即total.isbn()函數(shù)既是total.bookNo。
成員函數(shù)通過一個名為this的額外的隱式參數(shù)來訪為調(diào)用它的哪個對象,當(dāng)我們調(diào)用一個成員函數(shù)時,用請求該函數(shù)的對象地址初始化this。例如如果調(diào)用total.isbn(),則編譯器負(fù)責(zé)把total的地址傳遞給isbn的隱式形參this,可以等價的認(rèn)為編譯器將該調(diào)用重寫為了
其中調(diào)用Sales_data的isbn成員時傳入了total的地址。
在成員函數(shù)內(nèi)部,我們可以直接使用調(diào)用該函數(shù)的對象的成員,而無須通過成員訪問運(yùn)算符來做到這一點(diǎn),因?yàn)閠his所指的正好是這個對象,任何對類成員的直接訪問都被看做this的隱式引用,也就是說當(dāng)isbn使用bookNo時,他隱式的使用this指向的成員,就像我們書寫了this->bookNo。
對我們來說this形參是隱式定義的,實(shí)際上任何自定義名為this的參數(shù)或變量的行為都是非法的,我們可以在成員函數(shù)體內(nèi)部使用this,因此盡管沒有必要,但是我們還是能把isbn定義為下面的形式
因?yàn)閠his的目的總是指向“這個”對象,所以this是一個常量指針,我們不允許修改this中保存的地址。
引入const成員函數(shù)
isbn函數(shù)的另一個關(guān)鍵之處是緊隨參數(shù)列表之后的const,這里const的作用是修改隱式this指針的類型。
默認(rèn)情況下,this的類型是指向類類型非常量版本的常量指針,在上述例子中,this的類型是Sales_data *const,盡管const是隱式的,但他仍然需要遵循初始化規(guī)則,意味著我們不能把this綁定到一個常量對象上。這一情況也就使我們不能在一個常量對象上調(diào)用普通的成員函數(shù)。
如果isbn是一個普通函數(shù)而且this是一個普通的指針參數(shù),則我們應(yīng)該把this聲明稱const Sales_data *const,畢竟isbn的函數(shù)體內(nèi)不會改變this所指的對象,所以把this設(shè)置為指向常量的指針有助于提高函數(shù)的靈活性。
然而,this是隱式的并且不會出現(xiàn)在參數(shù)列表中,所以在哪兒將this聲明成指向常量的指針就成為我們必須面對的問題,C++允許把const放在成員變量的參數(shù)列表之后,此時緊跟在參數(shù)列表后的const表示this是一個指向常量的指針,像這樣使用const的成員函數(shù)被稱作常量成員函數(shù)。
因?yàn)閠his是指向常量的指針,所以常量成員函數(shù)不能改變調(diào)用他的對象的內(nèi)容,即isbn只能讀取調(diào)用他的對象的數(shù)據(jù)成員,不能寫。
注意:常量對象、常量對象的引用或指針都只能調(diào)用常量成員函數(shù)。
類作用域和成員函數(shù)
類的成員函數(shù)定義嵌套在類的作用域之內(nèi),因此isbn中用到的bookNo其實(shí)就是定義在Sales_data內(nèi)的數(shù)據(jù)成員。
注意:即使bookNo定義在isbn之后isbn還是可以使用bookNo,因?yàn)榫幾g器分兩步處理類,首先編譯成員的聲明,然后才輪到成員函數(shù)體。
在類的外部定義成員函數(shù)
與其他函數(shù)一樣,我們在類外定義成員函數(shù)時必須和聲明匹配,即返回列表、參數(shù)列表、函數(shù)名和聲明一致。
如果成員被聲明成常量成員函數(shù),那么它的定義也必須在參數(shù)列表后明確指定const屬性,同時類外部定義的成員的名字必須包含他所屬的類名。
units_sold和revenue其實(shí)隱式的使用了Sales_data的成員。
定義一個返回this對象的函數(shù)
函數(shù)combine的設(shè)計(jì)類似于+=,調(diào)用該函數(shù)的對象代表的是賦值運(yùn)算符左側(cè)的對象,右側(cè)對象則通過顯式的實(shí)參被傳入函數(shù)。
當(dāng)我們調(diào)用
total的地址被綁定到隱式的this參數(shù)上,而rhs綁定到了trans上,因此上述語句等價于把trans.units_sold加到total.units_sold上。
值得注意的是,我們的返回類型和返回語句,如前面所述,我們無須使用隱式的this指針訪問函數(shù)調(diào)用者的某個具體成員,而是需要把調(diào)用函數(shù)的對象當(dāng)作一個整體來訪問。所以用解引符解引this來返回調(diào)用這個函數(shù)的對象,即total。
這一章基本是把C++ primer上的原文照搬下來了,確實(shí)非常的重要和難以理解(對作者來說