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不需要分別定義,否則將它用於值不能替換的場景中,必須提供一條定義語句,類內部提供了初始值,類外部不能在制定一個初始值了
靜態數據成員的類型可以是不完全類型,可以是他所屬的類類型,但是普通成員只能聲明所屬類的指針或者引用;另一個區別是靜態成員可以作為默認實參