- 成員函數(shù)一個(gè)名為this的額外隱式參數(shù)來訪問調(diào)用它的那個(gè)對(duì)象。當(dāng)我們調(diào)用一個(gè)成員函數(shù)時(shí)拱烁,編譯器負(fù)責(zé)把對(duì)象的地址傳遞給隱式參數(shù)this籽懦。this實(shí)際上是一個(gè)常量指針,不允許改變this中的地址镐作。
- 跟隨在成員函數(shù)參數(shù)列表之后的const關(guān)鍵字表示this是一個(gè)指向常量的指針招拙。這種使用const的成員函數(shù)被稱作常量成員函數(shù)(const member function)
- 常量對(duì)象以及常量對(duì)象的引用或指針都只能調(diào)用常量成員函數(shù)洞斯。
- 類本身就是一個(gè)作用域朗徊,類的成員函數(shù)的定義嵌套在類的作用域之內(nèi)报慕,成員函數(shù)可以隨意使用類中的其他成員而無須在意出現(xiàn)次序蝠嘉。
- 在類的外部定義成員函數(shù)時(shí)缘回,成員函數(shù)的定義必須與它的聲明匹配秽誊,如果成員函數(shù)被聲明為常量成員函數(shù)错览,那么定義也必須在參數(shù)列表后指定const屬性
double Sales_data::avg_price() const{
.....
}
- 可以通過*this來返回執(zhí)行該成員函數(shù)的對(duì)象
- 類的成員通常需要定義一些輔助函數(shù)理澎,這些函數(shù)定義的操作概念上屬于類的接口的組成部分逞力,但實(shí)際上不屬于類的本身。這些函數(shù)的聲明一般應(yīng)與類聲明在同一個(gè)頭文件內(nèi)矾端。
- 類通過一個(gè)或幾個(gè)特殊的成員函數(shù)來控制其對(duì)象的初始化過程掏击,這些函數(shù)叫做構(gòu)造函數(shù)(constructor),構(gòu)造函數(shù)名字和類名相同秩铆,但是沒有返回類型砚亭。
- 構(gòu)造函數(shù)不能被聲明為const的,當(dāng)我們創(chuàng)建一個(gè)類的const對(duì)象時(shí)殴玛,直到構(gòu)造函數(shù)完成初始化過程捅膘,對(duì)象才能真正取得“常量”屬性。因此滚粟,構(gòu)造函數(shù)在const對(duì)象的構(gòu)造過程中可以向其寫值寻仗。
- 類通過一個(gè)特殊的構(gòu)造函數(shù)來控制默認(rèn)初始化過程,這個(gè)函數(shù)叫做默認(rèn)構(gòu)造函數(shù)(default constructor)凡壤,默認(rèn)構(gòu)造函數(shù)無需任何實(shí)參署尤。
- 如果我們的類沒有顯式定義構(gòu)造函數(shù)耙替,編譯器就會(huì)隱式地定義一個(gè)默認(rèn)構(gòu)造函數(shù),又被稱為合成的默認(rèn)構(gòu)造函數(shù)(synthesized default constructor)曹体,對(duì)大多數(shù)類型來說俗扇,這個(gè)函數(shù)按照如下規(guī)則初始化類的數(shù)據(jù)成員;
- 如果存在類內(nèi)初始值箕别,用它來初始化成員铜幽。
- 否則,默認(rèn)初始化該成員串稀。
- 對(duì)于一個(gè)普通的類來說除抛,必須定義它自己的默認(rèn)構(gòu)造函數(shù)。
- 如果類中包含其他類類型的成員且該成員的類型沒有默認(rèn)構(gòu)造函數(shù)母截,那么編譯器將無法生成默認(rèn)構(gòu)造函數(shù)到忽。
- C++11標(biāo)準(zhǔn)中,如果我們需要默認(rèn)的行為微酬,那么可以通過在參數(shù)列表后面寫上=default來要求編譯器生成構(gòu)造函數(shù)绘趋。
Sales_data() = default;
=default既可以和聲明一起在類的內(nèi)部,也可以作為定義在類的外部颗管。和其他函數(shù)一樣,如果在類的內(nèi)部滓走,則默認(rèn)構(gòu)造函數(shù)是內(nèi)聯(lián)的垦江;如果它在類的外部,則默認(rèn)情況下不是內(nèi)聯(lián)的搅方。
- 構(gòu)造函數(shù)初始值列表(constructor initialize list)負(fù)責(zé)為新創(chuàng)建的對(duì)象的一個(gè)或幾個(gè)數(shù)據(jù)成員賦初值比吭。
Sales_data(const string &s):bookNo(s),units_sold(0),revenue(0){}
- 沒有出現(xiàn)在構(gòu)造函數(shù)初始值列表中的成員將通過相應(yīng)的類內(nèi)初始值(如果存在的話)初始化,或者執(zhí)行默認(rèn)初始化姨涡。如果不支持類內(nèi)初始值衩藤,則所有構(gòu)造函數(shù)都應(yīng)該顯式地初始化每個(gè)內(nèi)置類型的成員。
- 除了定義類的對(duì)象如何初始化外涛漂,類還需要控制拷貝赏表,賦值,銷毀對(duì)象時(shí)發(fā)生的行為匈仗。對(duì)象在幾種情況下會(huì)被拷貝瓢剿,如我們初始化變量以及以值得方式傳遞或返回一個(gè)對(duì)象等。如果我們不主動(dòng)定義這些操作悠轩,編譯器將替我們合成它們间狂。一般來說,生成的版本將對(duì)對(duì)象的每個(gè)成員執(zhí)行拷貝火架,賦值和銷毀操作鉴象。
- 一個(gè)類可以包括0個(gè)或多個(gè)訪問說明符(public忙菠,private)
- 使用class和struct定義類唯一的區(qū)別就是默認(rèn)的訪問權(quán)限。struct默認(rèn)為public纺弊,而class默認(rèn)為private
- 類可以允許其他類或者函數(shù)訪問它的非公有成員牛欢,方法是令其他類或者函數(shù)成為它的友元(friend)。如果類想把函數(shù)作為它的友元俭尖,只需要增加一條以friend關(guān)鍵字開始的函數(shù)聲明語句即可:
class Sales_data{
friend Sales_data add(const Sales_data&, const Sales_data&);
...
}
友元聲明只能出現(xiàn)在類定義的內(nèi)部氢惋,但是具體位置不限。友元不是類的成員也不受區(qū)域訪問控制級(jí)別的約束稽犁。一般來說焰望,最好在類定義開始或結(jié)束前的位置集中聲明友元。
- 友元的聲明僅僅指定了訪問的權(quán)限已亥,而非一個(gè)通常意義上的函數(shù)聲明熊赖。如果我們希望類的用戶能夠調(diào)用某個(gè)友元函數(shù),那么我們就必須在友元聲明之外再專門對(duì)函數(shù)進(jìn)行一次聲明虑椎。
- 除了定義數(shù)據(jù)和函數(shù)成員之外震鹉,類還可以自定義某種類型在類中的別名,其也存在訪問限制捆姜,可以是public或private传趾。
class Screen{
public:
typedef string::size_type pos;
....
}
用來定義類型的成員必須先定義后使用,因此類型成員通常出現(xiàn)在類開始的地方泥技。
- 定義在類內(nèi)部的函數(shù)是默認(rèn)內(nèi)聯(lián)的浆兰,也可以在類的內(nèi)部或外部用inline顯式聲明成員函數(shù)。不過珊豹,最好只在類外部定義的地方說明inline簸呈,便于理解。
- 如果我們希望修改類的某個(gè)數(shù)據(jù)成員店茶,即使是在一個(gè)const成員函數(shù)內(nèi)蜕便,可以通過在變量的聲明中加入mutable關(guān)鍵字。
- 可以通過是否為const實(shí)現(xiàn)多個(gè)成員函數(shù)的重載版本贩幻,這樣轿腺,const對(duì)象會(huì)調(diào)用const版本,非常量對(duì)象則調(diào)用非const版本段直。
- 我們可以把類名作為類型的名字使用吃溅,或者我們也可以把類名跟在關(guān)鍵字class或struct后面:
Sales_data item1;
class Sales_data item1; //一條等價(jià)的聲明
- 就像可以把函數(shù)的聲明和定義分離開一樣,我們也能僅聲明類而暫時(shí)不定義它:
class Screen;
- 除了把非成員函數(shù)定義為友元之外鸯檬,類還可以把其他類定義成友元决侈,也可以把其他類(之前已定義過的)的成員函數(shù)定義成友元。
class Screen{
friend class Window_mgr;
...
}
如果指定了友元類,則友元類的成員函數(shù)可以訪問此類所有成員赖歌。
class Screen{
friend void Window_mgr::clear();
...
}
要想令某個(gè)成員函數(shù)成為友元枉圃,需要仔細(xì)組織程序的結(jié)構(gòu)以滿足聲明和定義的彼此依賴關(guān)系:
- 先定義友元函數(shù)所屬的類,聲明友元函數(shù)但不定義
- 定義需要友元函數(shù)的類庐冯,包括對(duì)友元函數(shù)的友元聲明
- 最后定義友元函數(shù)孽亲,因?yàn)檫@樣才能使用另一個(gè)類的成員。
- 類和非成員函數(shù)的聲明不是必須在它們的友元聲明之前展父。當(dāng)一個(gè)名字出現(xiàn)在一個(gè)友元聲明時(shí)返劲,我們隱式地假定改名字在當(dāng)前作用域中是可見的。友元函數(shù)可以在類的內(nèi)部定義栖茉,但仍必須在類的外部提供相應(yīng)的聲明篮绿。本質(zhì)上友元聲明的作用是影響訪問權(quán)限,本身并非普通意義上的聲明吕漂。
- 一個(gè)類就是一個(gè)作用域亲配,所以我們在類外部定義成員函數(shù)必須同時(shí)提供類名和函數(shù)名。一旦遇到類名惶凝,定義的剩余部分就在類的作用域之內(nèi)了吼虎,所以可以直接使用類的成員。
- 類的定義分兩步處理:
- 編譯成員的聲明
- 直到類全部可見才編譯函數(shù)體
但是對(duì)于聲明使用的名字苍鲜,包括返回類型和參數(shù)思灰,都必須在聲明前確保可見混滔。如果某個(gè)成員的聲明使用了類中尚未出現(xiàn)的名字官辈,編譯器會(huì)在定義該類的作用域中(類定義之前)繼續(xù)查找。
- 如果類中成員使用了外層作用域中的某個(gè)名字遍坟,而該名字代表一種類型,則類不能在之后重新定義該名字晴股。
- 類型名的定義通常出現(xiàn)在類開始的地方愿伴,確保所有該類型的成員都出現(xiàn)在定義之后。
- 如果成員函數(shù)在外部定義电湘,則它還會(huì)考慮在成員函數(shù)定義之前和類定義之后的作用域中的聲明隔节。
- 如果沒有在構(gòu)造函數(shù)的初始值列表中顯式地初始化成員,則該成員將在構(gòu)造函數(shù)體之前執(zhí)行默認(rèn)初始化寂呛。即使在構(gòu)造函數(shù)中顯式賦值也并不是初始化而是賦值怎诫。
- 成員的初始化順序與它們在類定義中出現(xiàn)順序一致
- 如果一個(gè)構(gòu)造函數(shù)為所有參數(shù)都提供了默認(rèn)實(shí)參,則它也實(shí)際上定義了默認(rèn)構(gòu)造函數(shù)贷痪。
- C++11標(biāo)準(zhǔn)使得我們可以定義所謂的委托構(gòu)造函數(shù)幻妓,即使用所屬類的其他構(gòu)造函數(shù)執(zhí)行它自己的初始化過程。
class Sales_data{
Sales_data():Sales_data("",0,0){}
...
};
受委托的構(gòu)造函數(shù)的初始值列表和函數(shù)體被依次執(zhí)行劫拢,然后控制權(quán)才會(huì)交還給委托者的函數(shù)體肉津。
- 我們能夠?yàn)轭惗x隱式轉(zhuǎn)換機(jī)制强胰,如果構(gòu)造函數(shù)只接受一個(gè)實(shí)參,則它實(shí)際上定義了轉(zhuǎn)換為此類類型的隱式轉(zhuǎn)換機(jī)制妹沙,有時(shí)我們把這種構(gòu)造函數(shù)稱為轉(zhuǎn)換構(gòu)造函數(shù)偶洋。但需要注意的是:編譯器只會(huì)自動(dòng)地執(zhí)行一步類型轉(zhuǎn)換
- 我們可以通過將構(gòu)造函數(shù)聲明為explicit阻止隱式轉(zhuǎn)換。此時(shí)該構(gòu)造函數(shù)只能以直接初始化的形式使用距糖,即圓括號(hào)的形式玄窝。
- 聚合類使得用戶可以直接訪問其成員,當(dāng)一個(gè)類滿足一下條件時(shí)悍引,我們說它是聚合的:
- 所有成員都是public的
- 沒有定義任何構(gòu)造函數(shù)
- 沒有類內(nèi)初始值
- 沒有基類恩脂,也沒有virtual函數(shù)
struct Data {
int ival;
string s;
};
我們可以提供一個(gè)花括號(hào)括起來的成員初始值列表來初始化聚合類的數(shù)據(jù)成員
Data vall={0,"Kevin"};
- 通過在成員聲明之前加上static關(guān)鍵字使得其與類關(guān)聯(lián)在一起,稱為靜態(tài)成員吗铐。
- 我們既可以在類的內(nèi)部也可以在類的外部定義靜態(tài)成員函數(shù)东亦,擋在外部定義時(shí),不能重復(fù)static關(guān)鍵字唬渗,該關(guān)鍵字只出現(xiàn)在類內(nèi)部的聲明語句典阵。
- 因?yàn)殪o態(tài)數(shù)據(jù)成員不屬于類的任何一個(gè)對(duì)象,所以它們并不是在創(chuàng)建類的對(duì)象時(shí)被定義的镊逝。一般來說壮啊,我們不能在類的內(nèi)部初始化靜態(tài)成員。
- 通常情況下撑蒜, 靜態(tài)成員不應(yīng)該在類的內(nèi)部初始化歹啼。然而,我們可以為靜態(tài)成員提供const整數(shù)類型的類內(nèi)初始值座菠,不過要求靜態(tài)成員必須是constexpr狸眼。
- 靜態(tài)成員的類型可以就是它所屬的類類型,而非靜態(tài)成員不行浴滴。同時(shí)靜態(tài)成員可以作為默認(rèn)實(shí)參拓萌。