2010-11-9(晚上 類)
最簡單地說,類就是定義了一個新的類型和一個新的作用域。
在類內部定義的函數默認為inline.
Const成員(函數)不能改變其所操作的對象的數據成員。Const必須同時出現在聲明和定義中,若只出現在其中一處,就會出現一個編譯時錯誤。
類背后蘊含的基本思想是數據抽象和封裝。數據抽象是一種依賴于接口和實現分離的編程(和設計)技術。……封裝是一項將低層次的元素組合起來形成新的,高層次實體的技術。
在C++中,使用訪問標號來定義類的抽象接口和實現封裝。……類型的數據抽象視圖由其public成員定義。……private封裝了類型的實現細節。
并非所有類都必須是抽象的。……一些類,例如pair,確實沒有抽象接口。……盡管如此,這樣的類型通常還是有成員函數的。
設計類的接口是,設計者應該考慮的是如何方便類的使用;使用類的時候,設計者就不應該考慮類如何工作。
在類的外部定義inline的一個好處是可以使得類比較容易閱讀。
不完全類型只能用于定義指向該類型的指針及引用,或者用于聲明(而不是定義)使用該類型作為形參類型或返回類型的函數。
因為只有當類定義體完成后才能定義類,因此類不能具有自身類型的數據成員。然后,只要類名一出現就可以認為該類已聲明。因此,類的數據成員可以是指向自身的指針或引用。
定義對象時,將為其分配存儲空間,但(一般而言)定義類型時不進行存儲分配。
未知時間(類)
public的類型別名雜類體外使用需要作用域限定符;在類體外成員函數定義中,出現成員名之后,不用限定符。
Inline成員函數在類體成員類外聲明一次即可。類體內定義的成員函數默認為inline。
Const成員函數不能修改非mutable的數據成員。
Const類對象只能調用const成員函數。
成員函數可以返回本類對象及引用,指針。返回對象時可以設定const屬性。
定義類的時候不能具有自身類型的數據成員,但可以是指向自身類型的指針或引用。
一旦遇到右花括號,類的定義就結束了。
未知時間(同上)
const構造函數是不必要的。
構造函數的工作是初始化對象。
構造函數初始化式只在構造函數的定義中而不是聲明中指定。
從概念上講,可以認為構造函數分兩個階段執行:(1)初始化階段;(2)普通的計算階段。
在構造函數初始化列表中沒有顯示提及的每個成員,使用與初始化變量相同的規則來進行初始化。運行該類型的默認構造函數,來初始化類類型的數據成員。內置或復合類型的成員初始化值依賴于對象的作用域:在局部作用域中這些成員不被初始化,而在全局作用域中它們被初始化為0。
必須對任何const或引用類型的成員以及沒有默認構造函數的類類型的任何成員使用初始化式。
構造函數初始化列表僅指定用于初始化成員的值,并不指定這些初始化執行的次序。成員被初始化的次序就是定義成員的次序。
初始化的次序常常無關緊要。然而,如果一個成員是根據其他成員而初始化,則成員初始化的次序是至關重要的。
安裝與成員聲明一致的次序編寫構造函數初始化列表是個好主意。此外,盡可能避免使用成員來初始化其他成員。
初始化式可以是任意表達式。
只要定義一個對象時沒有提供初始化式,就使用默認構造函數。為所有形參提供默認實參的構造函數也定義了默認構造函數。
實際上,如果定義了其他構造函數,則提供一個默認構造函數幾乎總是對的。
可以用單個實參來調用的構造函數定義了從形參類型到該類型的一個隱式轉換。
當構造函數被聲明為explicit時,編譯器將不使用它作為轉換操作符。
任何構造函數都可以用來顯示地創建臨時對象。
通常,除非有明顯的理由想要定義隱式轉換,否則,但形參構造函數應該為explicit。將構造函數設置為explicit可以避免錯誤,并且當轉換有用時,用戶可以顯示地構造對象。
每個static數據成員是與類關聯的對象,并不與該類的對象相關聯。
Static成員函數沒有this形參,它可以直接訪問所屬類的static數據成員,但不能直接使用非static成員。
因為static成員不是任何對象的組成部分,所以static成員函數不能被聲明為const。畢竟,將成員函數聲明為const就是承諾不會修改該函數所屬的對象。
Static數據成員的類型可以是該成員所屬的類類型。Static數據成員可用作默認實參。
友元聲明將已命名的類或非成員函數引入到外圍作用域中。用友元引入的類名和函數(定義或聲明),可以像預先聲明一樣使用。
————————————————————————————————————————————————已打印———————————————————————————————————————————————————
2010-11-26晚(復制控制)
1,復制構造函數,賦值操作符和析構函數總稱為復制控制。
2,實現復制控制操作最困難的部分,往往在于識別何時需要覆蓋默認版本。
3,c++支持兩種初始化形式:直接初始化和復制初始化。
4,合成復制構造函數直接復制內置類型成員的值,類類型成員使用該類的復制構造函數進行復制。數組成員的復制是個例外。雖然一般不能復制數組。但如果一個類具有數組成員,則合成復制構造函數將復制數組。
5,為了防止復制,類必須顯式聲明其復制構造函數為private。想要連友元和成員中的復制也禁止,就可以聲明一個(private)復制構造函數但不對其定義。
6,通過聲明(但不定義)private復制構造函數,可以禁止任何復制類類型對象的嘗試:用戶代碼中的復制嘗試將在編譯時標記為錯誤。而成員函數和友元函數中的復制嘗試將在鏈接時導致錯誤。
7,如果定義了復制構造函數,也必須定義默認構造函數。
8,實際上,應將這兩個操作(復制和賦值)看做是一個單元。如果需要其中一個,我們幾乎也可以肯定需要另一個。
9,變量在超出作用域時應該自動撤銷……動態分配的對象只有在指向該對象的指針被刪除時才撤銷。……撤銷一個容器(不管是標準庫容器還是內置數組)時,也會運行容器中的類類型元素的析構函數)
10,析構函數通常用于釋放再構造函數或在對象生命期內獲取的資源。
11,如果類需要析構函數,則它也需要賦值操作符和復制構造函數,這是一個有用的經驗法則。這個規則常稱為三法則,指的是如果需要析構函數,則需要所有這三個復制控制成員。
12,與復制構造函數或賦值操作符不同,編譯器總是會為我們合成一個析構函數。
13,合成析構函數并不刪除指針成員所指向的對象。
14,析構函數與復制構造函數或賦值操作符之間的一個重要區別是,即使我們編寫了自己的析構函數,合成析構函數仍然運行。
15,復制控制的賦值操作符接收單個形參,且該形參是同一類類型對象。
2011-4-4(中午)重載操作符與轉換
1,用于內置類型的操作符,其含義不能改變。
2,操作符的優先級,結合性或操作數數目不能改變。
3,重載操作符并不保證操作數的求值順序。
4,一般將算術和關系操作符頂以為非成員函數,而將賦值操作符定義為成員。
5,操作符定義為非成員函數時,通常必須將他們設置為所操作類的友元。
6,重載逗號,取地址,邏輯與,邏輯或等操作通常不是好做法。這些操作具有有用的內置含義,如果定義了自己的版本,就不能再使用這些內置含義。
7,賦值,下標,調用(()),和成員訪問箭頭等操作符必須定義為成員,將這些操作符定義為非成員函數將導致編譯時錯誤。
8,對稱的操作數,如算術操作符,相等操作符,關系操作符和位操作符,最好定義為普通非成員函數。
9,當定義符合標準庫iostream規范的輸入或輸出操作符的時候,必須使它成為非成員操作符。
10,與輸出操作符類似,輸入操作符的第一個形參是一個引用,指向它要讀的流,并且返回的也是對同一個流的引用。它的第二個形參是對要讀入的對象的非const引用,該形參必須為非const,因為輸入操作符的目的是將數據讀到這個對象中。
11,更重要但通常重視不夠的是,輸入和輸出操作符有如下區別:輸入操作符必須處理錯誤和文件結束的可能性。
12,設計輸入操作符時,如果可能,要確定錯誤恢復措施,這很重要。
13,注意,為了與內置操作符保持一致,加法返回一個右值,而不是一個引用。
14,類賦值操作符必須是類的成員,以便編譯器可以知道是否需要合成一個。
15,下標操作符必須定義為類成員函數。
16,類定義下標操作符時,一般需要定義兩個版本:一個為非const成員并返回引用,另一個為const成員并返回const引用。
17,箭頭操作符必須定義為類成員函數。解引用操作符不要求定義為成員,但將它作為成員一般也是正確的。
18,重載箭頭操作符必須返回指向類類型的指針,或者返回定義了自己的箭頭操作符的類類型對象。
19,C++語言不要求自增操作符或自減操作符一定作為類的成員,但是,因為這些操作符改變對象的狀態,所以更傾向于將它們作為成員。
20,為了與內置類型一致,前綴式操作符應返回被增量或減量對象的引用。
21,后綴式操作符函數接受一個額外的(即無用的)int型形參。
22,為了與內置操作符一致,后綴式操作符應返回舊值,并且,應作為值返回,而不是返回引用。
23,如果想要使用函數調用來調用后綴式操作符,必須給出一個整型實參值。
ps:做這些筆記的時候是一年前多了。當時還在做著ACM,學這些似乎只是抱著充實自己的心態,當時最想的似乎就是看完整本書,但最終還是在面向對象的部分停下來了。現在很多東西都忘了,畢竟這樣學而沒有實際使用,肯定很容易忘的。可能當時也是出現了這么個想法而停下來的吧,至少應該是其中一個原因。這份筆記似乎在硬盤里丟失過一次,最后在金山快盤里找回來的。2011-12-4