本文博客園地址:http://www.cnblogs.com/xiongxuanwen/p/4290086.html
一、C++類的定義
C++中使用關(guān)鍵字class來定義類, 其基本形式如下:
class 類名
{
public:
protected:
private:
};
示例:
定義一個(gè)點(diǎn)(Point)類, 具有以下屬性和方法:
■ 屬性: x坐標(biāo), y坐標(biāo)
■ 方法: 1.設(shè)置x,y的坐標(biāo)值; 2.輸出坐標(biāo)的信息。
實(shí)現(xiàn)代碼:
class Point
{
public:
void setPoint(int x, int y);
void printPoint();
private:
int xPos;
int yPos;
};
代碼說明:
上段代碼中定義了一個(gè)名為 Point 的類, 具有兩個(gè)私密屬性, int型的xPos和yPos, 分別用來表示x點(diǎn)和y點(diǎn)。
在方法上,setPoint用來設(shè)置屬性, 也就是 xPos 和 yPos 的值;printPoint用來輸出點(diǎn)的信息。
1 數(shù)據(jù)抽象和封裝
抽象是通過特定的實(shí)例抽取共同特征以后形成概念的過程。一個(gè)對(duì)象是現(xiàn)實(shí)世界中一個(gè)實(shí)體的抽象,一個(gè)類是一組對(duì)象的抽象。
封裝是將相關(guān)的概念組成一個(gè)單元,然后通過一個(gè)名稱來引用它。面向?qū)ο蠓庋b是將數(shù)據(jù)和基于數(shù)據(jù)的操作封裝成一個(gè)整體對(duì)象,對(duì)數(shù)據(jù)的訪問或修改只能通過對(duì)象對(duì)外提供的接口進(jìn)行。
2 類定義
幾個(gè)重要名詞:
(1) 類名
遵循一般的命名規(guī)則; 字母,數(shù)字和下劃線組合,不要以數(shù)字開頭。
(2) 類成員
類可以沒有成員,也可以定義多個(gè)成員。成員可以是數(shù)據(jù)、函數(shù)或類型別名。所有的成員都必須在類的內(nèi)部聲明。
沒有成員的類是空類,空類也占用空間。
class?People
{
};
sizeof(People) = 1;
(3) 構(gòu)造函數(shù)
構(gòu)造函數(shù)是一個(gè)特殊的、與類同名的成員函數(shù),用于給每個(gè)數(shù)據(jù)成員設(shè)置適當(dāng)?shù)某跏贾怠?/p>
(4) 成員函數(shù)
成員函數(shù)必須在類內(nèi)部聲明,可以在類內(nèi)部定義,也可以在類外部定義。如果在類內(nèi)部定義,就默認(rèn)是內(nèi)聯(lián)函數(shù)。
3 類定義補(bǔ)充
3.1 可使用類型別名來簡(jiǎn)化類
除了定義數(shù)據(jù)和函數(shù)成員之外,類還可以定義自己的局部類型名字。
使用類型別名有很多好處,它讓復(fù)雜的類型名字變得簡(jiǎn)單明了、易于理解和使用,還有助于程序員清楚地知道使用該類型的真實(shí)目的。
classPeople
{
public:
typedef std::stringphonenum;//電話號(hào)碼類型
phonenumphonePub; //公開號(hào)碼
private:
phonenumphonePri;//私人號(hào)碼
};
3.2?成員函數(shù)可被重載
可以有多個(gè)重載成員函數(shù),個(gè)數(shù)不限。
3.3內(nèi)聯(lián)函數(shù)
有三種:
(1)直接在類內(nèi)部定義。
(2)在類內(nèi)部聲明,加上inline關(guān)鍵字,在類外部定義。
(3)在類內(nèi)部聲明,在類外部定義,同時(shí)加上inline關(guān)鍵字。注意:此種情況下,內(nèi)聯(lián)函數(shù)的定義通常應(yīng)該放在類定義的同一頭文件中,而不是在源文件中。這是為了保證內(nèi)聯(lián)函數(shù)的定義在調(diào)用該函數(shù)的每個(gè)源文件中是可見的。
3.4 訪問限制
public,private,protected為屬性/方法限制的關(guān)鍵字。
3.5 類的數(shù)據(jù)成員中不能使用 auto、extern和register等進(jìn)行修飾, 也不能在定義時(shí)進(jìn)行初始化
如int xPos = 0;?//錯(cuò);
例外:
靜態(tài)常量整型(包括char,bool)數(shù)據(jù)成員可以直接在類的定義體中進(jìn)行初始化,例如:
static const int ia= 30;
4 類聲明與類定義
4.1 類聲明(declare)
classScreen;
在聲明之后,定義之前,只知道Screen是一個(gè)類名,但不知道包含哪些成員。只能以有限方式使用它,不能定義該類型的對(duì)象,只能用于定義指向該類型的指針或引用,聲明(不是定義)使用該類型作為形參類型或返回類型的函數(shù)。
void Test1(Screen& a){};
void Test1(Screen* a){};
4.2 類定義(define)
在創(chuàng)建類的對(duì)象之前,必須完整的定義該類,而不只是聲明類。所以,類不能具有自身類型的數(shù)據(jù)成員,但可以包含指向本類的指針或引用。
classLinkScreen
{
public:
Screen?window;
LinkScreen* next;
LinkScreen* prev;
因?yàn)樵陬惗x之后可以接一個(gè)對(duì)象定義列表,可類比內(nèi)置類型,定義必須以分號(hào)結(jié)束:
classLinkScreen{ /* ... */ };
classLinkScreen{ /* ... */ } scr1,scr2;
5 類對(duì)象
定義類對(duì)象時(shí),將為其分配存儲(chǔ)空間。
Sales_item item;//編譯器分配了足以容納一個(gè) Sales_item 對(duì)象的存儲(chǔ)空間。item 指的就是那個(gè)存儲(chǔ)空間。
6 隱含的 this 指針
成員函數(shù)具有一個(gè)附加的隱含形參,即?this指針,它由編譯器隱含地定義。成員函數(shù)的函數(shù)體可以顯式使用 this 指針。
6.1 何時(shí)使用 this 指針
當(dāng)我們需要將一個(gè)對(duì)象作為整體引用而不是引用對(duì)象的一個(gè)成員時(shí)。最常見的情況是在這樣的函數(shù)中使用 this:該函數(shù)返回對(duì)調(diào)用該函數(shù)的對(duì)象的引用。
class Screen
{
...
public:
Screen& set(char);
};
Screen& Screen::set(char c)
{
contents[cursor] = c;
return *this;
}
7?類作用域
每個(gè)類都定義了自己的作用域和唯一的類型。
類的作用域包括:類的內(nèi)部(花括號(hào)之內(nèi)), 定義在類外部的成員函數(shù)的參數(shù)表(小括號(hào)之內(nèi))和函數(shù)體(花括號(hào)之內(nèi))。
class Screen
{
//類的內(nèi)部
...
};
//類的外部
char Screen::get(index r, index c) const
{
index row = r * width;????? // compute the row location
return contents[row + c];?? // offset by c to fetch specified?character
}
注意:成員函數(shù)的返回類型不一定在類作用域中??赏ㄟ^ 類名::來判斷是否是類的作用域,::之前不屬于類的作用域,::之后屬于類的作用域。例如
Screen:: 之前的返回類型就不在類的作用域,Screen:: 之后的函數(shù)名開始到函數(shù)體都是類的作用域。
class Screen
{
public:
typedef std::string::size_type index;
indexget_cursor() const;
};
Screen::indexScreen::get_cursor() const ? //注意:index前面的Screen不能少
{
return cursor;
}
該函數(shù)的返回類型是 index,這是在 Screen 類內(nèi)部定義的一個(gè)類型名。在類作用域之外使用,必須用完全限定的類型名 Screen::index 來指定所需要的 index 是在類 Screen 中定義的名字。
二 構(gòu)造函數(shù)
構(gòu)造函數(shù)是特殊的成員函數(shù),用來保證每個(gè)對(duì)象的數(shù)據(jù)成員具有合適的初始值。
構(gòu)造函數(shù)名字與類名相同,不能指定返回類型(也不能定義返回類型為void),可以有0-n個(gè)形參。
在創(chuàng)建類的對(duì)象時(shí),編譯器就運(yùn)行一個(gè)構(gòu)造函數(shù)。
1 構(gòu)造函數(shù)可以重載
可以為一個(gè)類聲明的構(gòu)造函數(shù)的數(shù)量沒有限制,只要每個(gè)構(gòu)造函數(shù)的形參表是唯一的。
class Sales_item;
{
public:
Sales_item(const std::string&);
Sales_item(std::istream&);
Sales_item(); //默認(rèn)構(gòu)造函數(shù)
};
2 構(gòu)造函數(shù)自動(dòng)執(zhí)行
只要?jiǎng)?chuàng)建該類型的一個(gè)對(duì)象,編譯器就運(yùn)行一個(gè)構(gòu)造函數(shù):
Sales_item item1("0-201-54848-8");
Sales_item *p = new Sales_item();
第一種情況下,運(yùn)行接受一個(gè) string 實(shí)參的構(gòu)造函數(shù),來初始化變量item1。
第二種情況下,動(dòng)態(tài)分配一個(gè)新的 Sales_item 對(duì)象,通過運(yùn)行默認(rèn)構(gòu)造函數(shù)初始化該對(duì)象。
3 構(gòu)造函數(shù)初始化式
與其他函數(shù)一樣,構(gòu)造函數(shù)具有名字、形參表和函數(shù)體。
與其他函數(shù)不同的是,構(gòu)造函數(shù)可以包含一個(gè)構(gòu)造函數(shù)初始化列表:
Sales_item::Sales_item(const string &book):isbn(book), units_sold(0), revenue(0.0)
{ }
構(gòu)造函數(shù)初始化列表以一個(gè)冒號(hào)開始,接著是一個(gè)以逗號(hào)分隔的數(shù)據(jù)成員列表,每個(gè)數(shù)據(jù)成員后面跟一個(gè)放在圓括號(hào)中的初始化式。
構(gòu)造函數(shù)可以定義在類的內(nèi)部或外部。構(gòu)造函數(shù)初始化只在構(gòu)造函數(shù)的定義中指定。
構(gòu)造函數(shù)分兩個(gè)階段執(zhí)行:(1)初始化階段;(2)普通的計(jì)算階段。初始化列表屬于初始化階段(1),構(gòu)造函數(shù)函數(shù)體中的所有語句屬于計(jì)算階段(2)。
初始化列表比構(gòu)造函數(shù)體先執(zhí)行。不管成員是否在構(gòu)造函數(shù)初始化列表中顯式初始化,類類型的數(shù)據(jù)成員總是在初始化階段初始化。
3.1 哪種類需要初始化式
const 對(duì)象或引用類型的對(duì)象,可以初始化,但不能對(duì)它們賦值,而且在開始執(zhí)行構(gòu)造函數(shù)的函數(shù)體之前要完成初始化。
初始化 const 或引用類型數(shù)據(jù)成員的唯一機(jī)會(huì)是構(gòu)造函數(shù)初始化列表中,在構(gòu)造函數(shù)函數(shù)體中對(duì)它們賦值不起作用。
沒有默認(rèn)構(gòu)造函數(shù)的類類型的成員,以及 const 或引用類型的成員,必須在初始化列表中完成初始化。
class ConstRef
{
public:
ConstRef(int ii);
private:
int i;
constint ci;
int &ri;
};
ConstRef::ConstRef(int ii)
{
i = ii; ? // ok
ci = ii; ?// error
ri = i; ? //
}
應(yīng)該這么初始化:
ConstRef::ConstRef(int ii): i(ii), ci(i), ri(ii) { }
3.2 成員初始化的次序
每個(gè)成員在構(gòu)造函數(shù)初始化列表中只能指定一次。重復(fù)初始化,編譯器一般會(huì)有提示。
成員被初始化的次序就是定義成員的次序,跟初始化列表中的順序無關(guān)。
3.3 初始化式表達(dá)式
初始化式可以是任意表達(dá)式
Sales_item(const std::string &book, int cnt, doubleprice): isbn(book), units_sold(cnt), revenue(cnt * price) { }
3.4 類類型的數(shù)據(jù)成員的初始化式
初始化類類型的成員時(shí),要指定實(shí)參并傳遞給成員類型的一個(gè)構(gòu)造函數(shù),可以使用該類型的任意構(gòu)造函數(shù)。
Sales_item(): isbn(10, '9'), units_sold(0), revenue(0.0) {}
3.5?類對(duì)象的數(shù)據(jù)成員的初始化
在類A的構(gòu)造函數(shù)初始化列表中沒有顯式提及的每個(gè)成員,使用與初始化變量相同的規(guī)則來進(jìn)行初始化。
類類型的數(shù)據(jù)成員,運(yùn)行該類型的默認(rèn)構(gòu)造函數(shù)來初始化。
內(nèi)置或復(fù)合類型的成員的初始值依賴于該類對(duì)象的作用域:在局部作用域中不被初始化,在全局作用域中被初始化為0。假設(shè)有一個(gè)類A,
class A
{
public:
int ia;
B b;
};
A類對(duì)象A a;不管a在局部作用域還是全局作用域,b使用B類的默認(rèn)構(gòu)造函數(shù)來初始化,ia的初始化取決于a的作用域,a在局部作用域,ia不被初始化,a在全局作用域,ia初始化0。
4 默認(rèn)構(gòu)造函數(shù)
不含形參的構(gòu)造函數(shù)就是默認(rèn)構(gòu)造函數(shù)。
只要定義一個(gè)對(duì)象時(shí)沒有提供初始化式,就使用默認(rèn)構(gòu)造函數(shù)。如: A a;
為所有形參提供默認(rèn)實(shí)參的構(gòu)造函數(shù)也定義了默認(rèn)構(gòu)造函數(shù)。例如:
class A
{
public:
A(int a=1,char c =''){}
private:
int ia;
char c1;
};
4.1 合成的默認(rèn)構(gòu)造函數(shù)
只有當(dāng)一個(gè)類沒有定義構(gòu)造函數(shù)時(shí),編譯器才會(huì)自動(dòng)生成一個(gè)默認(rèn)構(gòu)造函數(shù)。
一個(gè)類只要定義了一個(gè)構(gòu)造函數(shù),編譯器也不會(huì)再生成默認(rèn)構(gòu)造函數(shù)。
建議:
如果定義了其他構(gòu)造函數(shù),也提供一個(gè)默認(rèn)構(gòu)造函數(shù)。
如果類包含內(nèi)置或復(fù)合類型(如 int& 或 string*)的成員,它應(yīng)該定義自己的構(gòu)造函數(shù)來初始化這些成員。每個(gè)構(gòu)造函數(shù)應(yīng)該為每個(gè)內(nèi)置或復(fù)合類型的成員提供初始化。
5 隱式類類型轉(zhuǎn)換
5.1?只含單個(gè)形參的構(gòu)造函數(shù)能夠?qū)崿F(xiàn)從形參類型到該類類型的一個(gè)隱式轉(zhuǎn)換
class A
{
public:
A(int a)
{
ia =a;
}
bool EqualTo(const A& a)
{
return ia == a.ia;
}
private:
int ia;
};
A a(1);
bool bEq = false;
bEq =a.EqualTo(1);//參數(shù)為1,實(shí)現(xiàn)從int型到A的隱式轉(zhuǎn)換
5.2抑制由構(gòu)造函數(shù)定義的隱式轉(zhuǎn)換
通過將構(gòu)造函數(shù)聲明為explicit,來防止在需要隱式轉(zhuǎn)換的上下文中使用構(gòu)造函數(shù):
class A
{
public:
explicitA(int a )
{
ia =a;
}
bool EqualTo(const A& a)
{
return ia == a.ia;
}
private:
int ia;
};
通常,除非有明顯的理由想要定義隱式轉(zhuǎn)換,否則,單形參構(gòu)造函數(shù)應(yīng)該為 explicit。將構(gòu)造函數(shù)設(shè)置為 explicit 可以避免錯(cuò)誤。
三 復(fù)制控制
1 復(fù)制構(gòu)造函數(shù)
1.1 幾個(gè)要點(diǎn)
(1) 復(fù)制構(gòu)造函數(shù)
復(fù)制構(gòu)造函數(shù)是一種特殊構(gòu)造函數(shù),只有1個(gè)形參,該形參(常用 const &修飾)是對(duì)該類類型的引用。
class Peopel
{
public:
Peopel();//默認(rèn)構(gòu)造函數(shù)
Peopel(const Peopel&);//復(fù)制構(gòu)造函數(shù)
~Peopel();//析構(gòu)函數(shù)
};
當(dāng)定義一個(gè)新對(duì)象并用一個(gè)同類型的對(duì)象對(duì)它進(jìn)行初始化時(shí),將顯式使用復(fù)制構(gòu)造函數(shù)。
Peopel?a1;?Peopel?a2 = a1;
當(dāng)將該類型的對(duì)象傳遞給函數(shù)或函數(shù)返回該類型的對(duì)象時(shí),將隱式使用復(fù)制構(gòu)造函數(shù)。
Peopel?Func(Peopel?b){...}
(2)析構(gòu)函數(shù)
析構(gòu)函數(shù)是構(gòu)造函數(shù)的互補(bǔ):當(dāng)對(duì)象超出作用域或動(dòng)態(tài)分配的對(duì)象被刪除時(shí),將自動(dòng)應(yīng)用析構(gòu)函數(shù)。
析構(gòu)函數(shù)可用于釋放構(gòu)造對(duì)象時(shí)或在對(duì)象的生命期中所獲取的資源。
不管類是否定義了自己的析構(gòu)函數(shù),編譯器都自動(dòng)執(zhí)行類中非 static 數(shù)據(jù)成員的析構(gòu)函數(shù)。
(3) 復(fù)制控制
復(fù)制構(gòu)造函數(shù)、賦值操作符和析構(gòu)函數(shù)總稱為復(fù)制控制。編譯器自動(dòng)實(shí)現(xiàn)這些操作,但類也可以定義自己的版本。
(4)?兩種初始化形式
C++ 支持兩種初始化形式:直接初始化和復(fù)制初始化。直接初始化將初始化式放在圓括號(hào)中,復(fù)制初始化使用 = 符號(hào)。
對(duì)于內(nèi)置類型,例如int, double等,直接初始化和復(fù)制初始化沒有區(qū)別。
對(duì)于類類型:直接初始化直接調(diào)用與實(shí)參匹配的構(gòu)造函數(shù);復(fù)制初始化先使用指定構(gòu)造函數(shù)創(chuàng)建一個(gè)臨時(shí)對(duì)象,然后用復(fù)制構(gòu)造函數(shù)將那個(gè)臨時(shí)對(duì)象復(fù)制到正在創(chuàng)建的對(duì)象。直接初始化比復(fù)制初始化更快。
(5)形參和返回值
當(dāng)形參或返回值為類類型時(shí),由該類的復(fù)制構(gòu)造函數(shù)進(jìn)行復(fù)制。
(6)初始化容器元素
復(fù)制構(gòu)造函數(shù)可用于初始化順序容器中的元素。例如:
vector svec(5);
編譯器首先使用 string 默認(rèn)構(gòu)造函數(shù)創(chuàng)建一個(gè)臨時(shí)值,然后使用復(fù)制構(gòu)造函數(shù)將臨時(shí)值復(fù)制到 svec 的每個(gè)元素。
(7)構(gòu)造函數(shù)與數(shù)組元素
如果沒有為類類型數(shù)組提供元素初始化式,則將用默認(rèn)構(gòu)造函數(shù)初始化每個(gè)元素。
如果使用常規(guī)的花括號(hào)括住的數(shù)組初始化列表來提供顯式元素初始化式,則使用復(fù)制初始化來初始化每個(gè)元素。根據(jù)指定值創(chuàng)建適當(dāng)類型的元素,然后用復(fù)制構(gòu)造函數(shù)將該值復(fù)制到相應(yīng)元素:
Sales_item primer_eds[] = { string("0-201-16487-6"),
string("0-201-54848-8"),
string("0-201-82470-1"),
Sales_item()
};
1.2?合成的復(fù)制構(gòu)造函數(shù)
(1)合成的復(fù)制構(gòu)造函數(shù)
如果沒有定義復(fù)制構(gòu)造函數(shù),編譯器就會(huì)為我們合成一個(gè)。
合成復(fù)制構(gòu)造函數(shù)的行為是,執(zhí)行逐個(gè)成員初始化,將新對(duì)象初始化為原對(duì)象的副本。
逐個(gè)成員初始化:合成復(fù)制構(gòu)造函數(shù)直接復(fù)制內(nèi)置類型成員的值,類類型成員使用該類的復(fù)制構(gòu)造函數(shù)進(jìn)行復(fù)制。
例外:如果一個(gè)類具有數(shù)組成員,則合成復(fù)制構(gòu)造函數(shù)將復(fù)制數(shù)組。復(fù)制數(shù)組時(shí)合成復(fù)制構(gòu)造函數(shù)將復(fù)制數(shù)組的每一個(gè)元素。
1.3 定義自己的復(fù)制構(gòu)造函數(shù)
(1) 只包含類類型成員或內(nèi)置類型(但不是指針類型)成員的類,無須顯式地定義復(fù)制構(gòu)造函數(shù),也可以復(fù)制。
class Peopel
{
public:
std::string name;
unsigned int id;
unsigned int age;
std::string address;
};
(2) 有些類必須對(duì)復(fù)制對(duì)象時(shí)發(fā)生的事情加以控制。
例如,類有一個(gè)數(shù)據(jù)成員是指針,或者有成員表示在構(gòu)造函數(shù)中分配的其他資源。而另一些類在創(chuàng)建新對(duì)象時(shí)必須做一些特定工作。這兩種情況下,都必須定義自己的復(fù)制構(gòu)造函數(shù)。
最好顯式或隱式定義默認(rèn)構(gòu)造函數(shù)和復(fù)制構(gòu)造函數(shù)。如果定義了復(fù)制構(gòu)造函數(shù),必須定義默認(rèn)構(gòu)造函數(shù)。
1.4 禁止復(fù)制
有些類需要完全禁止復(fù)制。例如,iostream 類就不允許復(fù)制。延伸:容器內(nèi)元素不能為iostream
為了防止復(fù)制,類必須顯式聲明其復(fù)制構(gòu)造函數(shù)為 private。
2 賦值操作符
與復(fù)制構(gòu)造函數(shù)一樣,如果類沒有定義自己的賦值操作符,則編譯器會(huì)合成一個(gè)。
(1)重載賦值操作符
Sales_item&operator=(const Sales_item &);
(2)合成賦值操作符
合成賦值操作符會(huì)逐個(gè)成員賦值:右操作數(shù)對(duì)象的每個(gè)成員賦值給左操作數(shù)對(duì)象的對(duì)應(yīng)成員。除數(shù)組之外,每個(gè)成員用所屬類型的常規(guī)方式進(jìn)行賦值。對(duì)于數(shù)組,給每個(gè)數(shù)組元素賦值。
(3)復(fù)制和賦值常一起使用
一般而言,如果類需要復(fù)制構(gòu)造函數(shù),它也會(huì)需要賦值操作符。
3 析構(gòu)函數(shù)
構(gòu)造函數(shù)的用途之一是自動(dòng)獲取資源;與之相對(duì)的是,析構(gòu)函數(shù)的用途之一是回收資源。除此之外,析構(gòu)函數(shù)可以執(zhí)行任意類設(shè)計(jì)者希望在該類對(duì)象的使用完畢之后執(zhí)行的操作。
(1) 何時(shí)調(diào)用析構(gòu)函數(shù)
撤銷(銷毀)類對(duì)象時(shí)會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)。
變量(類對(duì)象)在超出作用域時(shí)應(yīng)該自動(dòng)撤銷(銷毀)。
動(dòng)態(tài)分配的對(duì)象(new A)只有在指向該對(duì)象的指針被刪除時(shí)才撤銷(銷毀)。
撤銷(銷毀)一個(gè)容器(不管是標(biāo)準(zhǔn)庫(kù)容器還是內(nèi)置數(shù)組)時(shí),也會(huì)運(yùn)行容器中的類類型元素的析構(gòu)函數(shù)(容器中的元素總是從后往前撤銷)。
(2)何時(shí)編寫顯式析構(gòu)函數(shù)
如果類需要定義析構(gòu)函數(shù),則它也需要定義賦值操作符和復(fù)制構(gòu)造函數(shù),這個(gè)規(guī)則常稱為三法則:如果類需要析構(gòu)函數(shù),則需要所有這三個(gè)復(fù)制控制成員。
(3)合成析構(gòu)函數(shù)
合成析構(gòu)函數(shù)按對(duì)象創(chuàng)建時(shí)的逆序撤銷每個(gè)非 static 成員,因此,它按成員在類中聲明次序的逆序撤銷成員。
對(duì)于每個(gè)類類型的成員,合成析構(gòu)函數(shù)調(diào)用該成員的析構(gòu)函數(shù)來撤銷對(duì)象。
合成析構(gòu)函數(shù)并不刪除指針成員所指向的對(duì)象。 所以,如果有指針成員,一定要定義自己的析構(gòu)函數(shù)來刪除指針。
析構(gòu)函數(shù)與復(fù)制構(gòu)造函數(shù)或賦值操作符之間的一個(gè)重要區(qū)別:即使我們編寫了自己的析構(gòu)函數(shù),合成析構(gòu)函數(shù)仍然運(yùn)行。
四 友元
友元機(jī)制允許一個(gè)類將對(duì)其非公有成員的訪問權(quán)授予指定的函數(shù)或類。
友元可以出現(xiàn)在類定義的內(nèi)部的任何地方。
友元不是授予友元關(guān)系的那個(gè)類的成員,所以它們不受聲明出現(xiàn)部分的訪問控制影響。
建議:將友元聲明成組地放在類定義的開始或結(jié)尾。
1 友元類
class Husband
{
public:
friendclass Wife;
private:
double money;//錢是老公私有的,別人不能動(dòng),但老婆除外
};
class Wife
{
public:
void Consume(Husband& h)
{
h.money -= 10000;//老婆可以花老公的錢
}
};
Husband h;
Wife w;
w.Consume(h);
2?使其他類的成員函數(shù)成為友元
class Husband;//1.聲明Husband
class Wife//2.定義Wife類
{
public:
void Consume(Husband& h);
};
class Husband//3.定義Husband類
{
public:
friend void Wife::Consume(Husband& h);//聲明Consume函數(shù)。
private:
double money;//錢是老公私有的,別人不能動(dòng),但老婆除外
};
void Wife::Consume(Husband& h)//4.定義Consume函數(shù)。
{
h.money -= 10000;//老婆可以花老公的錢
}
注意類和函數(shù)的聲明和定義的順序:
(1)聲明類Husband
(2)定義類Wife,聲明Consume函數(shù)
(3)定義類Husband
(4)定義Consume函數(shù)。
五 static 類成員
static 成員,有全局對(duì)象的作用,但又不破壞封裝。
1 static 成員變量
static 數(shù)據(jù)成員是與類關(guān)聯(lián)的對(duì)象,并不與該類的對(duì)象相關(guān)聯(lián)。
static 成員遵循正常的公有/私有訪問規(guī)則。
2 使用 static 成員而不是全局對(duì)象有三個(gè)優(yōu)點(diǎn)。
(1) ?static 成員的名字是在類的作用域中,因此可以避免與其他類的成員或全局對(duì)象名字沖突。
(2) ?可以實(shí)施封裝。static 成員可以是私有成員,而全局對(duì)象不可以。
(3) ?通過閱讀程序容易看出 static 成員是與特定類關(guān)聯(lián)的,這種可見性可清晰地顯示程序員的意圖。
3 static 成員函數(shù)
在類的內(nèi)部聲明函數(shù)時(shí)需要添加static關(guān)鍵字,但是在類外部定義函數(shù)時(shí)就不需要了。
因?yàn)閟tatic 成員是類的組成部分但不是任何對(duì)象的組成部分,所以有以下幾個(gè)特點(diǎn):
1) static 函數(shù)沒有 this 指針
2) static 成員函數(shù)不能被聲明為 const (將成員函數(shù)聲明為 const 就是承諾不會(huì)修改該函數(shù)所屬的對(duì)象)
3) static 成員函數(shù)也不能被聲明為虛函數(shù)
4 static 數(shù)據(jù)成員
static 數(shù)據(jù)成員可以聲明為任意類型,可以是常量、引用、數(shù)組、類類型,等等。
static 數(shù)據(jù)成員必須在類定義體的外部定義(正好一次),并且應(yīng)該在定義時(shí)進(jìn)行初始化。
建議:定義在類的源文件中名,即與類的非內(nèi)聯(lián)函數(shù)的定義同一個(gè)文件中。注意,定義時(shí)也要帶上類類型+"::"
double Account::interestRate = 0.035;
5 特殊的靜態(tài)常量整型成員
靜態(tài)常量整型數(shù)據(jù)成員可以直接在類的定義體中進(jìn)行初始化,例如:
static const int period = 30;
當(dāng)然char 可以轉(zhuǎn)換成整形,也是可以的,staticconst charbkground= '#';
6 其他
(1)static 數(shù)據(jù)成員的類型可以是該成員所屬的類類型。非 static 成員只能是自身類對(duì)象的指針或引用
classScreen
{
public:
// ...
private:
staticScreen src1; // ok
Screen?*src2;?????? // ok
Screen?src3;??????? // error
};
(2)非 static 數(shù)據(jù)成員不能用作默認(rèn)實(shí)參,static 數(shù)據(jù)成員可用作默認(rèn)實(shí)參
class Screen
{
public:
Screen& clear(char =bkground);
private:
staticconst charbkground= '#';//static const整形變量可以在類內(nèi)部初始化。
};