1. 程式人生 > >第七章 類 c++primer

第七章 類 c++primer

c++中使用類定義自己的資料型別。
資料抽象幫助將物件的具體實現與物件能執行的操作分離開來
類的基本思想是資料抽象和封裝。
資料抽象是一種依賴於介面和實現分離的程式設計技術

類的介面包括使用者所能執行的操作;類的實現包括類的資料成員、負責介面實現的函式體以及定義類所需的各種私有函式

封裝實現了類的介面和實現的分離

類要實現資料抽象和封裝,必須首先定義一個抽象資料型別

7.1定義抽象資料型別
引入this:使得成員函式可以使用呼叫這個函式的物件的成員

引入const 成員函式:this是一個指向類型別的非常量版本的常量指標type(或者class) * const;所以不能繫結到一個常量物件上,隨意導致常量物件不能呼叫普通成員函式,這就需要this指向常量物件;對於普通函式而且this是一個普通指標可以這樣宣告this:const Sales_data *const;但是this是隱式的不會出現在引數列表;所以要選擇一個位置來將this宣告為指向常量的指標,c++讓const跟在函式引數列表後面來解決,這樣的成員函式稱為常量成員函式

常量物件,常量物件的引用或指標都只能呼叫常量成員函式

類作用域和成員函式:
類本身是一個作用域,類的成員函式巢狀定義在類作用域內,編譯器處理類時分兩步:先編譯成員宣告,然後才是成員函式,所以成員函式可以隨意使用成員名,無須在意宣告順序

在類的外部定義的成員函式:
在外部定義的成員函式必須與她在類內的宣告匹配,包括返回型別,引數列表函式名,如果被宣告稱常量成員函式引數列表後加const,類外部定義的成員的名字必須包含所屬的類名(使用作用域運算子)。

定義一個返回this物件的函式:如combine類似於+=
return *this;return語句解引用this指標獲得呼叫該函式的物件

7.1.3定義類相關的非成員函式
這些函式屬於類介面的組成部分,但又不屬於類本身。

定義它們的方式與普通函式一樣,生命和定義分開,宣告和類宣告放在同一個標頭檔案內;
預設情況下拷貝類物件拷貝的是物件的資料成員

7.1.4 建構函式:初始化物件
任務:初始化類物件的資料成員,無論何時只要類的物件被建立就會執行建構函式;
特點:名字和類名相同,沒有返回型別;其他與普通函式類似

建構函式沒有不能被宣告成const,建構函式在const物件構造過程中可以向其寫值

定義建構函式:
。。。=default;//c++11新規定指定預設建構函式,可以和類宣告一起出現在類內部,也可以作為類定義出現在類外部

建構函式初始值列表:她負責為建構函式新建的物件的一個或幾個資料成員賦初值。建構函式初始值是成員名字的一個列表每個名字後面緊跟括號括起來的(或者在花括號內的)成員初始值;不同成員初始值用逗號隔開。
函式體是空的,這是因為建構函式的唯一目的就是為資料成員賦初值

在類外部定義的建構函式:和其他成員函式一樣,外部定義的建構函式也必須指明建構函式是哪個類的成員,她執行建構函式體而沒有初始值列表;

7.1.5拷貝賦值析構
除了定義類物件初始化,類還要控制拷貝,賦值,銷燬物件時發生的行為
物件在幾種情況下會被拷貝:如初始化變數以及以值的方式傳遞或返回一個物件等

使用賦值運算子時會發生賦值

物件不再存在時執行銷燬操作

**很對需要動態記憶體的類能(而且應該)使用vector或者string物件管理必要的儲存空間

7.2訪問控制與封裝

public:定義類的介面,在整個程式內可見

private:該說明符之後的成員可以被類的成員函式訪問但是不能被使用該類的程式碼訪問

使用public和struct定義類的唯一區別是預設訪問許可權不同

7.2.1友元:提供了對類的非公有成員的訪問

必須在類定義內部宣告友元
一般來說最好最好在類定義的開始或結束前集中宣告友元(雖然不受類作用域約束)

友元的宣告僅僅指定了訪問許可權,而非普通意義上的函式宣告,如果我們希望類的使用者能夠呼叫某個友元函式,就必須在友元宣告之外再專門對函式進行一次宣告

7.3其他
除了定義書聚合函式成員之外,類還可以定義某種型別在類中的類型別名

inline可以在類內部宣告或者外部定義中使用關鍵inline;

無需在類宣告和定義的地方同時說明inline,最好只在類外部定義的地方宣告inline

可變資料成員:mutable即使在const物件中也可以改變她宣告的成員

類資料成員初始值
**類內初始值必須使用=的初始化形式或者花括號括起來的直接初始化形式

7.3.2返回*this的成員函式

7.3.4友元宣告和作用域
即使是用宣告友元的類的成員函式呼叫該友元函式,他也必須是被宣告過的

7.4類的作用域

作用域和定義在在類外部的成員:
一個類就是一個作用域的事實很好的解釋了為什麼當我們在類的外部定義成員函式時必須同時提供類名和函式名;類的外部成員名字被隱藏了

聲明瞭類名之後,定義的剩餘部分就在類的作用域內了,包括引數列表和函式體,可以直接使用無需再次授權了,但是函式的返回型別通常出現在函式名之前,所以如果函式定義在類的外部,返回型別使用的名字都位於類的作用域之外,必須指明

7.4.1名字查詢與類的作用域
名字查詢:尋找與所用名字最匹配的宣告的過程,從所在快開始,只向前查詢,由內向外;

定義在類內部的成員函式,解析其中的名字方式與上述查詢規則有所區別;
類的定義分兩步:
* 首先,編譯成員的宣告,
* 直到類全部可見後才編譯函式體,
編譯器處理完全部宣告之後才會處理函式定義

兩階段的處理方式只適用於成員函式中使用的名字。宣告中使用的名字,包括返回型別或者引數列表中使用的名字,都必須使用前確保可見

型別名的定義通常出現在類的開始處,這樣就能確保所用使用該型別的成員都出現類名定義之後

成員函式內使用的名字的 解析順序:函式內查詢,函式所在的類內查詢,類外查詢,如果類內有成員與函式用的名字同名,但是我們想要的是外部的這時可以使用全域性作用域運算子: , ::

7.5建構函式再談
如果成員是const,引用或者屬於某種未提供預設建構函式的類型別,我們必須通過建構函式初始值列表為這些成員提供初值

建議:使用建構函式初始值(初始化和賦值的區別,初始化直接初始化資料成員,而賦值是先初始化,在賦值,所以養成使用建構函式初始值的習慣.

成員初始化的順序建構函式初始值列表只說明初始化成員的值,並不限定初始化的具體順序,成員初始化的順序與他們在類定義中出現的順序一致,第一個成員先初始化,然後第二個。。

最好另建構函式初始化順序與成員函式宣告順序相同,最好不要用一個成員去初始化其他成員

預設是慘和建構函式:

委託建構函式:他使用自己所屬類的其他建構函式執行他自己的初始化過程,他把自己的一些職責委託給了其他建構函式,何其她建構函式一樣她也有一個初始值列表和一個函式體

7.5.3預設建構函式的作用
物件被預設初始化或值初始化時自動執行預設建構函式,預設建構函式在以下情形使用:
* 在塊作用域內不使用任何初始值定義一個非靜態變數或者陣列時
* 當一個類本身含有類型別的成員且使用合成的預設建構函式時
* 當類型別的成員沒有在建構函式初始值列表中顯示初始化時
* 當陣列初識化過程中我們提供的初始值數量少於陣列大小時
* 我們不使用初始值定義一個區域性靜態變數是

7.5.4隱式的類型別轉換

能通過一個實參呼叫的建構函式定義了一條從建構函式實參型別到類型別隱式轉換的規則
* 只允許一步類型別轉換
* 類型別轉換不總是有效

抑制建構函式定義的隱式轉換:將建構函式宣告為explicit
explicit建構函式只能用於直接初始化,不能用於拷貝初始化的過程

為轉換顯示的使用建構函式

7.5.5聚合類
所有成員public,沒有建構函式,沒有類內初始值,沒有基類虛擬函式,他的初始化是使用花括號括起來的成員初始值列表,初始值的順序必須與宣告順序一致;

7.5.6字面值常量類
資料成員都是字面值型別的聚合類是字面值常量類:

PS:常量表達式是指值不會改變並且編譯過程就能得到結果的表示式,顯然字面值常量是,用常量表達式初始化的const物件也是
字面值型別:算術型別,引用,指標都是字面值型別、列舉也是、字面值常量類
constexpr函式:能用於常量表達式的函式,他的返回型別,引數型別都是字面值常量,函式中有且只有一條返回語句,她在編譯過程中就可以得到結果;

constexpr建構函式:儘管建構函式不能是const的但字面值常量類的建構函式可以是constexpr

7.6類的靜態成員
讓某些成員與類相關而不是物件:通過在成員宣告前加上static使其與類關聯在一起,靜態成員可以是public也可以是private,靜態資料成員可以是常量引用指標類型別等
某個類的靜態資料物件為該類所有物件共享;

類似,靜態成員函式也不與任何物件繫結在一起,他們不包括this指標,也就不能宣告成const

使用類的靜態成員:使用作用域運算子直接訪問靜態成員

雖然靜態成員物件不屬於類的某個物件,但是我們可以使用物件,引用,指標來訪問靜態成員

函式定義內,成員函式不用使用作用域運算子就能訪問靜態成員

定義靜態成員
和其他成員函式一樣,既可以在類的內部定義也可以在類的外部定義成員函式,擋在外部定義時,不能重複關鍵字static,該關鍵字只能在類內部宣告語句出現;

靜態資料成員不屬於任何一個物件,她們並不是在建立類的物件時被定義的,她們不是有建構函式初始化的,而且一般來說,不能在類的內部初始化靜態資料,必須在外部定義和初始化每個靜態成員,
double Acount::interestRate=initRate();
interestRate是Acount的靜態成員,型別double,從類名開始這條定義語句就在類的作用域內了,所以可以直接使用initRate()函式,雖然她是私有的,但是可以用來初始化interestRate

最好把靜態資料成員的定義與其他非行內函數的定義放在同一個檔案中

靜態成員的類內初始化:要求靜態成員必須是字面值常量型別的constepr,初始值必須是常量表達式;
如果僅限於編譯器可以替換她的值的使用場景,則初始化一個const或者constexpr static不需要分別定義,否則將它用於值不能替換的場景中,必須提供一條定義語句,類內部提供了初始值,類外部不能在制定一個初始值了

靜態資料成員的型別可以是不完全型別,可以是他所屬的類型別,但是普通成員只能宣告所屬類的指標或者引用;另一個區別是靜態成員可以作為預設實參