第5章-數(shù)據(jù)共享和成員特性課件_第1頁
第5章-數(shù)據(jù)共享和成員特性課件_第2頁
第5章-數(shù)據(jù)共享和成員特性課件_第3頁
第5章-數(shù)據(jù)共享和成員特性課件_第4頁
第5章-數(shù)據(jù)共享和成員特性課件_第5頁
已閱讀5頁,還剩36頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第5章數(shù)據(jù)共享和成員特性5.1靜態(tài)成員5.2友元5.3成員其他特性5.4this指針5.5綜合應(yīng)用實例:棧類靜態(tài)操作5.1靜態(tài)成員使用靜態(tài)數(shù)據(jù)成員可以節(jié)省內(nèi)存,因為它是所有對象所公有的,因此,對多個對象來說,靜態(tài)數(shù)據(jù)成員只存儲一處,供所有對象共享。靜態(tài)數(shù)據(jù)成員的值是可以修改的,但它對每個對象都是一樣的。1.定義和使用與靜態(tài)變量相似,靜態(tài)數(shù)據(jù)成員是靜態(tài)存儲(static)的,但定義一個靜態(tài)數(shù)據(jù)成員與一般靜態(tài)變量不一樣,它必須按下列2步進(jìn)行:(1)

在類中使用關(guān)鍵字static聲明靜態(tài)數(shù)據(jù)成員。在類中聲明靜態(tài)數(shù)據(jù)成員,僅僅是說明了靜態(tài)數(shù)據(jù)成員是類中的成員這個關(guān)系,即便用該類定義對象時,該靜態(tài)數(shù)據(jù)成員也不會分配內(nèi)存空間。因此可以說,類中聲明的靜態(tài)數(shù)據(jù)成員是一種形式上的虛的數(shù)據(jù)成員。靜態(tài)數(shù)據(jù)成員的實際定義是由下一步來完成。(2)

在類外為靜態(tài)數(shù)據(jù)成員分配內(nèi)存空間并初始化。類中數(shù)據(jù)成員的內(nèi)存空間是在對象定義時來分配的,但靜態(tài)數(shù)據(jù)成員的內(nèi)存空間是為所有該類對象所共享,只能分配一次,因而不能通過定義類對象的方式來分配,即其初值不通過構(gòu)造函數(shù)來制定,必須在類的外部作實際定義才能為所有對象共享,其定義格式如下: <數(shù)據(jù)類型><類名>::<靜態(tài)數(shù)據(jù)成員名>=<值>可見,在類外初始化的靜態(tài)數(shù)據(jù)成員與全局變量初始化格式相似,只是須指明它所屬的類。由于靜態(tài)數(shù)據(jù)成員的靜態(tài)屬性static已在類中聲明,因此在類外不可再指定static。例如:5.1.1靜態(tài)數(shù)據(jù)成員5.1.1靜態(tài)數(shù)據(jù)成員程序運行的結(jié)果如下:分析:(1)A中,由于使用了默認(rèn)參數(shù),因而使得默認(rèn)構(gòu)造函數(shù)和重載構(gòu)造函數(shù)定義成一個構(gòu)造函數(shù)。這種程序方法在實際應(yīng)用時要小心使用。(2)程序中,類CSum中的私有數(shù)據(jù)成員nSum被聲明成靜態(tài)的,由于類中聲明的nSum是虛的,因此它必須在類體外進(jìn)行實際定義。若不指定初值,則默認(rèn)為0。(3)main函數(shù)中,對象one初始化后,nSum值變?yōu)?2。對象two由于調(diào)用的是(a=0,b=0)的默認(rèn)構(gòu)造函數(shù),故nSum的值沒有變化,仍然是12(注意構(gòu)造函數(shù)體的語句“nSum+=a+b;”中的“+=”不是“=”)。因此,main函數(shù)中前面兩條輸出語句的結(jié)果都是輸出12。當(dāng)執(zhí)行“two.setSum(5);”后,nSum值被設(shè)為5。由于nSum是所有對象所共享,也就是說,nSum是所有對象的公共成員,因此對象one中的nSum的值也是5。

5.1.1靜態(tài)數(shù)據(jù)成員2.幾點說明(1)由于靜態(tài)數(shù)據(jù)成員在類中所作的聲明僅僅是一種聲明該成員是屬于哪個類的,它是形式上的虛的成員,還必須在類的外部作實際定義才能為所有對象共享,正因為如此,靜態(tài)數(shù)據(jù)成員的實際定義和初始化本身是不受public、private和protected等訪問屬性的限制。(2)靜態(tài)數(shù)據(jù)成員可看成是類中聲明、類外定義的靜態(tài)全局變量,因此它具有靜態(tài)生存期,在程序中從實際定義時開始產(chǎn)生,到程序結(jié)束時消失。也就是說,靜態(tài)數(shù)據(jù)成員的內(nèi)存空間不會隨對象的產(chǎn)生而分配,也不會隨對象的消失而釋放。當(dāng)然,靜態(tài)數(shù)據(jù)成員的內(nèi)存空間同樣不能在類的構(gòu)造函數(shù)中創(chuàng)建或是在析構(gòu)函數(shù)中釋放。(3)靜態(tài)數(shù)據(jù)成員是類中的成員,它的訪問屬性同普通數(shù)據(jù)成員一樣,可以為public、private和protected。當(dāng)靜態(tài)數(shù)據(jù)成員為public時,則在類外對該成員的訪問和引用可有2種方式,一是通過對象來引用,二是直接引用。當(dāng)直接引用時,應(yīng)使用下列格式:

<類名>::<靜態(tài)成員名>5.1.1靜態(tài)數(shù)據(jù)成員例如,有:

classCSum {… public: staticint

nSum; //聲明公有型靜態(tài)數(shù)據(jù)成員

};

int

CSum::nSum=0; //靜態(tài)數(shù)據(jù)成員的實際定義和初始化 則在main函數(shù)中可有下列引用:

intmain() {

CSumone;

one.nSum=10; //通過對象來引用

CSum::nSum=12; //直接引用

cout<<one.nSum<<endl; //輸出12 return0; }代碼中,引用公有型靜態(tài)數(shù)據(jù)成員nSum的2種方式都是合法的,也是等價的。5.1.2靜態(tài)成員函數(shù)靜態(tài)成員函數(shù)和靜態(tài)數(shù)據(jù)成員一樣,它們都屬于類的靜態(tài)成員,但它們都不專屬于某個對象的成員,而是所有對象所共享的成員。因此,對于公有型(public)靜態(tài)成員來說,除可用對象來引用外,還可通過“類名::成員”直接來引用。在類中,靜態(tài)數(shù)據(jù)成員可以被成員函數(shù)引用,也可以被靜態(tài)成員函數(shù)所引用。但反過來,靜態(tài)成員函數(shù)卻不能直接引用類中說明的非靜態(tài)成員。假如,靜態(tài)成員函數(shù)可以引用了類中的非靜態(tài)成員,例如:

classCSum { public: staticvoidChangeData(intdata) {

nSum=data; //錯誤:引用類中的非靜態(tài)成員

} public:

int

nSum; };

則當(dāng)執(zhí)行語句:

CSum::ChangeData(5); //合法的靜態(tài)成員引用5.1.2靜態(tài)成員函數(shù)時必然會出現(xiàn)編譯錯誤,這是因為此時CSum類的任何對象都還沒有創(chuàng)建,nSum數(shù)據(jù)成員根本就不存在。即使是創(chuàng)建了CSum類對象,此時這種形式的靜態(tài)成員函數(shù)調(diào)用根本無法確定函數(shù)中所引用的nSum是屬于哪個對象,因此靜態(tài)成員函數(shù)只能引用靜態(tài)數(shù)據(jù)成員,因為它們都是獨立于對象實例之外而為對象所共享的成員。下面來看一個示例,它是用靜態(tài)成員來實現(xiàn)數(shù)據(jù)插入、輸出和排序操作。同普通成員函數(shù),類中的靜態(tài)成員函數(shù)也可在類中聲明,而在類外實現(xiàn)。由于類CData中所有的成員都聲明成了靜態(tài)的,因此在main函數(shù)直接通過“類名::成員”的形式來引用其public成員,通過靜態(tài)成員函數(shù)Add在靜態(tài)數(shù)組成員data中設(shè)置并添加數(shù)組,每添加一次,靜態(tài)指針成員pCur的指向就向下移動一次,使其指向下一個數(shù)組元素的內(nèi)存空間。靜態(tài)成員函數(shù)Print和Sort分別將data數(shù)組中的已有數(shù)組輸出和排序。程序運行的結(jié)果如下:

可見,若將相同類別的操作均用公有型靜態(tài)成員函數(shù)來實現(xiàn),則無需通過對象就可引用類中的成員,此時的類成了一種工具集,這在強(qiáng)調(diào)程序算法的場合下得到了廣泛應(yīng)用。5.1.2靜態(tài)成員函數(shù)但是,靜態(tài)成員函數(shù)可以把類的引用或指針作為形參以間接訪問非靜態(tài)成員。例如:

[例Ex_VisitNonStatic]靜態(tài)成員函數(shù)間接訪問非靜態(tài)成員#include<iostream>usingnamespacestd;classCSum{public: staticint

getsum(CSum&obj);

int

addval(inta=1,intb=1) //非靜態(tài)成員函數(shù)

{ return(BaseVal+a+b); }private: staticint

BaseVal;};int

CSum::BaseVal=10;int

CSum::getsum(CSum&obj){

int

nSum=0;

nSum+=obj.addval(); //靜態(tài)成員函數(shù)getsum()使用引用obj來訪問非靜態(tài)成員函數(shù)addval() returnnSum;}intmain(){

CSuma;

cout<<CSum::getsum(a)<<endl; return0;}5.1.2靜態(tài)成員函數(shù)程序運行的結(jié)果如下:這種將引用或者指針作為靜態(tài)成員函數(shù)形參傳遞的用法,與非靜態(tài)成員函數(shù)里this指針(后面討論)的功能有異曲同工之妙。需要強(qiáng)調(diào)的是:(1)靜態(tài)成員中的“靜態(tài)(static)”與普通靜態(tài)變量和靜態(tài)函數(shù)中的“靜態(tài)”含義是不一樣的。普通靜態(tài)變量中的“靜態(tài)”是使用靜態(tài)存儲內(nèi)存空間,而類中的靜態(tài)數(shù)據(jù)成員的“靜態(tài)”是對象數(shù)據(jù)共享的聲明,并非具有實際意義的靜態(tài)存儲內(nèi)存空間。普通靜態(tài)函數(shù)中的“靜態(tài)”是表示本程序文件的內(nèi)部函數(shù),而類中的靜態(tài)成員函數(shù)的“靜態(tài)”表示該成員函數(shù)僅能訪問靜態(tài)數(shù)據(jù)成員,是為所有該類對象共享的聲明方式。(2)類的靜態(tài)數(shù)據(jù)成員的內(nèi)存開辟和釋放只能通過靜態(tài)成員函數(shù)來實現(xiàn),而不能通過類的構(gòu)造函數(shù)和析構(gòu)函數(shù)來完成。C++中也沒有靜態(tài)構(gòu)造函數(shù)和靜態(tài)析構(gòu)函數(shù)。

5.2友元通常,類的私有型(private)數(shù)據(jù)成員和保護(hù)型(protected)數(shù)據(jù)成員只能在類中由該類的成員函數(shù)來訪問,類的對象以及外部函數(shù)只能訪問類的公有型(public)成員函數(shù),類的私有和保護(hù)型數(shù)據(jù)成員只能通過類的成員函數(shù)來訪問,如圖5.1(a)所示。但是,如果在類中用friend關(guān)鍵字聲明一個函數(shù),且該函數(shù)的形參中還有該類的對象形參,這個函數(shù)便可通過形參對象或通過在函數(shù)體中定義該類對象來訪問該類的任何私有和保護(hù)型數(shù)據(jù)成員,如圖5.1(b)所示。這就好比一個人的私密可以讓“密友”知道一樣,用friend聲明的這個函數(shù)就稱為這個類的友元函數(shù)。除友元函數(shù)外,友元還可以是類,即一個類可以作另一個類的友元,稱為友元類。例如,當(dāng)B類作為A類的友元時,這就意味著在B類中通過A類對象來訪問A類中的所有成員??梢?,采用友元機(jī)制,通過類對象可以訪問或引用類中的所有成員。這樣,即使通過友元來修改數(shù)據(jù)成員時,修改的也僅僅是某個對象的數(shù)據(jù)成員,從而既保證了類的封裝性,也為外部訪問類的私有和保護(hù)型成員提供了方便。5.2.1友元概述5.2.1友元概述classCPoint{public: voidPrint(); …private:

int

xPos,yPos; …};f()→

CPointX;外部函數(shù)不可訪問(a)無友元關(guān)系classCPoint{ friendf();public: voidPrint(); …private:

int

xPos,yPos; …};f()→

CPointX;指明友元關(guān)系(b)有友元關(guān)系圖5.1外部函數(shù)和友元對類成員的訪問關(guān)系

5.2.2友元函數(shù)友元函數(shù)可分為友元外部函數(shù)和友元成員函數(shù)。當(dāng)一個函數(shù)f是A類的友元時,若f還是另一個類B的成員函數(shù)時,則這樣的友元稱為友元成員函數(shù);若f不屬于任何類的成員,則這樣的友元稱為友元外部函數(shù)。友元外部函數(shù)常直接簡稱為友元函數(shù)。1.友元函數(shù)友元函數(shù)在類中定義的格式如下:

friend<函數(shù)類型><函數(shù)名>(形參表) {…}從格式中可以看出,友元函數(shù)和類的成員函數(shù)定義格式基本一樣,只是友元函數(shù)前面用一個關(guān)鍵字friend來修飾。由于友元函數(shù)與類的關(guān)系是一種“友好(friendship)”關(guān)系,因此友元函數(shù)不屬于類中的成員函數(shù),它是在類中聲明的一個外部函數(shù)。需要說明的是:(1)友元函數(shù)的定義可在類中進(jìn)行,也可將友元函數(shù)在類中聲明,而將其實現(xiàn)在類外定義。但在類外定義時,不能像成員函數(shù)那樣指明它所屬的類。(2)由于友元函數(shù)是一個外部函數(shù),因此它對類中的成員訪問只能通過類對象來進(jìn)行,而不能直接去訪問。這里的對象可以通過形參來指定,也可在友元函數(shù)中進(jìn)行定義。(3)由于友元函數(shù)是類中聲明的外部函數(shù),因而它跟成員的訪問權(quán)限private、protected和public沒有任何關(guān)系,因此它的聲明可以出現(xiàn)在類中的任何部分,包括在private和public部分。但為了程序的可讀性,常將友元函數(shù)聲明在類體的開頭或是最后。5.2.2友元函數(shù)(4)由于友元函數(shù)不是類的成員,因此它在調(diào)用時不能指定其所屬的類,更不能通過對象來引用友元函數(shù)。(5)大多數(shù)外部函數(shù)對類中的數(shù)據(jù)操作是采用形參對象的方式,通過對象的“引用”傳遞,達(dá)到修改對象數(shù)據(jù)的目的。對于友元函數(shù),也應(yīng)該采用這種方式,只是友元函數(shù)還能修改對象的私有和保護(hù)型數(shù)據(jù)成員。下面來舉一個例子,它是通過友元函數(shù)將一個點(CPoint)的位置發(fā)生偏移。5.2.2友元函數(shù)

[例Ex_FriendFun]使用友元函數(shù)#include<iostream>usingnamespacestd;classCPoint{ friendCPoint

Inflate(CPoint&pt,int

nOffset); //聲明一個友元函數(shù)public:

CPoint(intx=0,inty=0) {

xPos=x; yPos=y; } voidPrint() {

cout<<"Point("<<xPos<<","<<yPos<<")"<<endl; }private:

int

xPos,yPos;};CPointInflate(CPoint&pt,int

nOffset) //友元函數(shù)的定義{

pt.xPos+=nOffset; //直接改變私有數(shù)據(jù)成員xPos和yPos

pt.yPos+=nOffset; returnpt;}intmain(){

CPointpt(10,20); pt.Print();

Inflate(pt,3); //直接調(diào)用友元函數(shù)

pt.Print(); return0;}5.2.2友元函數(shù)在類CPoint中,Inflate是在類中聲明,在類外定義的友元函數(shù)。它有兩個形參:一是引用形參對象pt,二是int形參變量nOffset。由于在友元函數(shù)中,對象的所有數(shù)據(jù)成員可以直接訪問,因此可直接將形參對象pt的私有數(shù)據(jù)成員直接加上nOffset指定的偏移量。由于Inflate指定的pt對象是引用傳遞,因此對pt內(nèi)容的修改也就是對實參對象內(nèi)容的修改。程序運行的結(jié)果如下:2.友元成員函數(shù)友元成員函數(shù)在類中定義的格式如下:

friend<函數(shù)類型><類名>::<函數(shù)名>(形參表) {…}由于友元成員函數(shù)還是另一個類的成員函數(shù),因此這里的類名是指它作為成員所在的類名。同成員函數(shù)一樣,友元成員函數(shù)的定義既可在類中進(jìn)行,也可將友元成員函數(shù)在類中聲明,而將其實現(xiàn)在類外定義。但在類外定義時,應(yīng)像成員函數(shù)那樣指明它所屬的類。例如:

5.2.2友元函數(shù)在類CRect中聲明了一個友元函數(shù)Inflate,由于它還是類CPoint的成員函數(shù),因此Inflate既可以直接訪問CPoint的所有成員,也可以通過CRect類對象訪問類CRect中的所有成員。由于在類CPoint中的Inflate函數(shù)的形參含有CRect對象,而此時CRect類還沒有定義,因此需要在類CPoint前先作CRect類的聲明,以便后面能使用CRect數(shù)據(jù)類型。程序運行的結(jié)果如下:

下面來看一個例子。在類CPoint的定義中,類COther被聲明成CPoint的友元類。這樣,在類COther中,可通過CPoint對象pt訪問類CPoint的所有成員。程序運行的結(jié)果如下:

5.2.3友元類總之:(1)友元關(guān)系反映了程序中類與類之間、外部函數(shù)和類之間、成員函數(shù)和另一個類等之間的關(guān)系,這個關(guān)系是單向的,即當(dāng)在CPoint中聲明COther是CPoint的友元類時,只能在COther類中通過CPoint對象訪問CPoint類的所有成員,而在CPoint類中是無法訪問COther類的私有和保護(hù)型成員。(2)一個類中的友元并非是該類的成員,由于“friend”關(guān)系,因而友元只能通過對象來訪問聲明友元所在類的成員。而靜態(tài)成員是類的一個成員,它本身具有不同的訪問屬性,只是對于公有靜態(tài)成員來說,它可以有對象訪問和“類名::靜態(tài)成員”2種等價的訪問方式。(3)與友元函數(shù)相比,靜態(tài)成員函數(shù)只是修改類的靜態(tài)數(shù)據(jù)成員,而對于友元來說,由于通過對象可以修改聲明友元所在類的所有數(shù)據(jù)成員,因而友元函數(shù)比靜態(tài)成員函數(shù)更加危險,而且友元類使這種危險更加擴(kuò)大。因此,在類程序設(shè)計中,靜態(tài)成員和友元一定要慎用!5.3成員其他特性關(guān)鍵字const不僅可以修飾數(shù)據(jù)成員,而且可以修飾成員函數(shù)。1.常數(shù)據(jù)成員在類中使用const關(guān)鍵字進(jìn)行聲明的數(shù)據(jù)成員,稱為常數(shù)據(jù)成員,其聲明格式如下: 數(shù)據(jù)類型const數(shù)據(jù)成員名; const數(shù)據(jù)類型數(shù)據(jù)成員名;上述兩種格式是等價的,都是用來聲明const數(shù)據(jù)成員。const除了修飾一般數(shù)據(jù)成員外,還可修飾引用數(shù)據(jù)成員和靜態(tài)數(shù)據(jù)成員,分別稱為常引用數(shù)據(jù)成員和常靜態(tài)數(shù)據(jù)成員。同const變量一樣,這些常數(shù)據(jù)成員的值都是不能被更新的,且必須進(jìn)行初始化。對于一般常數(shù)據(jù)成員和常引用數(shù)據(jù)成員來說,其初始化只能通過構(gòu)造函數(shù)中的成員初始化列表的方式來進(jìn)行。而對于靜態(tài)常數(shù)據(jù)成員來說,則須在類外進(jìn)行定義并初始化,初始化的方式和一般靜態(tài)數(shù)據(jù)成員相同。例如:5.3.1const成員5.3.1const成員

[例Ex_ConstData]常數(shù)據(jù)成員的使用#include<iostream>usingnamespacestd;classCOne{public:

COne(inta) :x(a),r(x) //常數(shù)據(jù)成員的初始化

{} voidPrint();public:

constint&r; //常引用數(shù)據(jù)成員private:

constintx; //常數(shù)據(jù)成員

staticconstinty; //靜態(tài)常數(shù)據(jù)成員};constint

COne::y=10; //靜態(tài)常數(shù)據(jù)成員的初始化voidCOne::Print(){

cout<<"x="<<x<<",y="<<y<<",r="<<r<<endl;}intmain(){

COneone(100);one.Print();

COnetwo(200);two.Print(); return0;}5.3.1const成員

程序中,類COne聲明了3個常數(shù)據(jù)成員,分別是一般常數(shù)據(jù)成員x、常靜態(tài)數(shù)據(jù)成員y和常引用數(shù)據(jù)成員r。要注意這些常數(shù)據(jù)成員的初始化方式,常靜態(tài)數(shù)據(jù)成員y是在類外進(jìn)行實際定義,其值設(shè)為10,而常數(shù)據(jù)成員x和常引用數(shù)據(jù)成員r通過成員初始化列表的方式來進(jìn)行,r的初值是引用a的內(nèi)存空間,但它們的值都取決于構(gòu)造函數(shù)的形參a。程序的運行結(jié)果如下:需要說明的是,常數(shù)據(jù)成員和常引用數(shù)據(jù)成員都是類中的數(shù)據(jù)成員,它們與其他成員一樣,也有private、public和protected訪問屬性。2.常成員函數(shù)使用const關(guān)鍵字進(jìn)行聲明的成員函數(shù),稱為常成員函數(shù),其聲明格式如下:

<類型說明符><函數(shù)名>(<參數(shù)表>)const;說明:(1)常成員函數(shù)聲明格式中,const是加在函數(shù)說明后面的類型修飾符,它是函數(shù)類型的一個組成部分,因此,在函數(shù)實現(xiàn)部分也要帶const關(guān)鍵字。

5.3.1const成員

(2)由于常成員函數(shù)是類中的成員,因此原則上在該函數(shù)中可以訪問類中的所有成員,但由于有了const限制,因而常成員函數(shù)不能修改任何數(shù)據(jù)成員,并且由于普通成員函數(shù)往往會更新數(shù)據(jù),因此在常成員函數(shù)中不能調(diào)用非const成員函數(shù)。(3)

只有常成員函數(shù)才有資格被常對象調(diào)用,由于常對象不能調(diào)用其他成員函數(shù),因此常成員函數(shù)是常對象唯一的對外接口方式。(4)const關(guān)鍵字可以作為重載函數(shù)的區(qū)分,例如:

voidprint(); voidprint()const;

是合法的重載函數(shù)。5.3.1const成員

[例Ex_ConstFunc]常成員函數(shù)的使用#include<iostream>usingnamespacestd;classCOne{public:

COne(inta=0,intb=0) { x=a;y=b; } voidprint(); voidprint()const; //聲明常成員函數(shù)private:

intx,y;};voidCOne::print(){

cout<<x<<","<<y<<endl;}voidCOne::print()const{

cout<<"使用常成員函數(shù):"<<x<<","<<y<<endl;}intmain(){

COneone(5,4);

one.print(); constCOnetwo(20,52);

two.print(); return0;}5.3.1const成員

程序中,類COne聲明了兩個重載成員函數(shù),一個帶const,一個不帶。由于one是一般對象,因此語句“one.print();”調(diào)用的是一般成員函數(shù)“voidprint();”,而two是常對象,因此“two.print();”調(diào)用的是常成員函數(shù)“voidprint()const;”。程序運行的結(jié)果如下:

5.3.2mutable成員關(guān)鍵字mutable是“易變的”意思,它與const關(guān)鍵字相對。前面已說過,在一個常成員函數(shù)中是不能對數(shù)據(jù)成員進(jìn)行更改的。但有些數(shù)據(jù)成員本身是不需要保護(hù)的,且又需要類來封裝時,mutable關(guān)鍵字就起了很大的作用。一個用mutable來修飾的數(shù)據(jù)成員永遠(yuǎn)處于“可變”的狀態(tài),即使在常成員函數(shù)中,也可以被修改,例如:5.3.2mutable成員

[例Ex_Mutable]Mutable數(shù)據(jù)成員的使用#include<iostream>usingnamespacestd;classCOne{public:

COne(inta=0,intb=0) { x=a;y=b; } voidprint(); voidprint()const; //聲明常成員函數(shù)private:

mutableintx,y; //mutable修飾的數(shù)據(jù)成員};voidCOne::print(){

cout<<x<<","<<y<<endl;}voidCOne::print()const{

x++; y++; //修改數(shù)據(jù)成員

cout<<"使用常成員函數(shù):"<<x<<","<<y<<endl;}intmain(){

COneone(5,4); one.print(); constCOnetwo(20,52); two.print(); return0;}5.3.2mutable成員程序運行的結(jié)果如下:需要說明的是:在ANSI/ISOC++中,mutable僅用作類中的數(shù)據(jù)成員的存儲類型。因此,它不能修飾成員函數(shù),也不能修飾類外的普通變量。當(dāng)mutable修飾數(shù)據(jù)成員時,它可被常成員函數(shù)修改。同樣,也可由常對象修改。如:

classA { public: mutableintx;

inty; }; constAa; //常對象

a.x=10; //合法

a.y=10; //錯誤,成員y不是mutable存儲類型mutable還可以修飾const、static數(shù)據(jù)成員,但不能修飾引用成員,并且當(dāng)mutable修飾const成員時,const應(yīng)緊隨mutable之后,例如:

classX { mutableconstint*p; //好

mutableint*constq; //不好

};

5.3.3explicit成員

關(guān)鍵字explicit是“顯式的”意思,它用于修飾類的構(gòu)造函數(shù)。在討論explicit用法之前,先來看看類CData的代碼。

classCData { public:

CData(intdata=0) {

m_nData=data; } ~CData() {} private:

int

m_nData; };當(dāng)用類CData定義對象并初始化時,可以有下列兩種等價形式:

CDataone(10); //A:顯式調(diào)用構(gòu)造函數(shù)

CDatatwo=10; //B:隱式調(diào)用構(gòu)造函數(shù)5.3.3explicit成員

對于B方式來說,當(dāng)“two=10;”時它實際上是隱式調(diào)用構(gòu)造函數(shù)“CData(intdata)”,從而使two對象的數(shù)據(jù)成員m_nData等于10。但這種方式有時會引起誤解,例如:

classCData { public:

CData(intdata=0) {

m_nData=data; }

CData(constchar*str) {

cout<<str<<endl; } ~CData() {} private:

int

m_nData; };

此時,若有

CDataa="a"; //隱式調(diào)用構(gòu)造函數(shù)5.3.3explicit成員

則很容易讓人誤解為是將對象a中的數(shù)據(jù)成員m_nData的值等于"a",會認(rèn)為因為類型不一致而導(dǎo)致錯誤產(chǎn)生。但實際上這種形式的初始化是合法的,由于它是調(diào)用構(gòu)造函數(shù)“CData(constchar*str)”,從而運行結(jié)果是輸出字符串“a”。但這恐怕并非是程序程序設(shè)計所要的結(jié)果,因此為了避免對象初始化采用隱式調(diào)用構(gòu)造函數(shù)的方式,在相應(yīng)的構(gòu)造函數(shù)前面加上關(guān)鍵字explicit,即:

classCData {… explicit CData(constchar*str) {

cout<<str<<endl; }

… };

這樣,當(dāng)

CDataa="a"; //不合法,編譯錯誤就會出現(xiàn)編譯錯誤。但顯示調(diào)用構(gòu)造函數(shù)的方式仍是合法的,即:

CData

b("a"); //合法5.4this指針在深入討論this指針之前,先來看一看類中成員函數(shù)的效率問題。1.引類CPoint代碼若有一個CPoint類,其代碼如下: 類CPoint用來描述一個平面上的點的信息。其中,定義的4個成員函數(shù)Add1~Add4的作用都是用來實現(xiàn)兩個2個點的加法操作,只不過它們的形參個數(shù)和返回類型不同而已。2.

成員函數(shù)的效率分析(1)成員函數(shù)Add1的原型如下:

CPointAdd1(CPointone,CPointtwo);對于該函數(shù)的使用,可有下列代碼:

CPointpt1(10,20),pt2(30,40); //語句A

CPointpt=pt.Add1(pt1,pt2); //語句B

pt.Print(); //輸出Point(40,60)

可見,為了在類外調(diào)用Add1函數(shù),定義了3個對象pt1、pt2和pt,這樣語句A和B共執(zhí)行了3次CPoint構(gòu)造函數(shù),且語句B還執(zhí)行3次CPoint默認(rèn)拷貝構(gòu)造函數(shù):pt1和pt2對象傳遞及函數(shù)Add1返回對象賦給pt。5.4.1成員函數(shù)的效率5.4.1成員函數(shù)的效率

(2)成員函數(shù)Add2的原型如下:

voidAdd2(CPointone,CPointtwo);對于該函數(shù)的使用,可有下列代碼:

CPointpt1(10,20),pt2(30,40),pt; //語句A pt.Add2(pt1,pt2); //語句B

pt.Print(); //輸出Point(40,60)同樣,為了在類外調(diào)用Add2函數(shù),定義了3個對象pt1、pt2和pt,這樣語句A執(zhí)行了3次CPoint構(gòu)造函數(shù),而語句B只執(zhí)行2次CPoint默認(rèn)拷貝構(gòu)造函數(shù):pt1和pt2對象傳遞。這樣,Add2函數(shù)的使用比Add1函數(shù)的使用少執(zhí)行了1次CPoint默認(rèn)拷貝構(gòu)造函數(shù),效率提高了一些。(3)成員函數(shù)Add3的原型如下:

CPointAdd3(CPointtwo);對于該函數(shù)的使用,可有下列代碼:

CPointpt(10,20),pt2(30,40); //語句A pt=pt.Add3(pt2); //語句B

pt.Print(); //輸出Point(40,60)5.4.1成員函數(shù)的效率

此時,為了在類外調(diào)用Add3函數(shù),定義了2個對象pt和pt2,這樣程序運行時執(zhí)行了2次CPoint構(gòu)造函數(shù)和2次CPoint默認(rèn)拷貝構(gòu)造函數(shù)。因此Add3函數(shù)的使用比Add2函數(shù)的使用又少執(zhí)行了1次CPoint構(gòu)造函數(shù),效率提高更多了一些。(4)成員函數(shù)Add4的原型如下:

voidAdd4(CPointtwo);對于該函數(shù)的使用,可有下列代碼:

CPointpt(10,20),pt2(30,40); //語句A pt.Add4(pt2); //語句B

pt.Print(); //輸出Point(40,60)這時,為了在類外調(diào)用Add4函數(shù),定義了2個對象pt和pt2,這樣程序運行時執(zhí)行了2次CPoint構(gòu)造函數(shù)和1次CPoint默認(rèn)拷貝構(gòu)造函數(shù)。因此Add4函數(shù)的使用比Add3函數(shù)的使用又少執(zhí)行了1次CPoint默認(rèn)拷貝構(gòu)造函數(shù),效率最高。5.4.1成員函數(shù)的效率上述執(zhí)行分析的結(jié)果可用表5.1來表示。 表5.1成員函數(shù)的效率分析成員函數(shù)調(diào)用需對象的個數(shù)調(diào)用默認(rèn)構(gòu)造函數(shù)的次數(shù)調(diào)用默認(rèn)拷貝構(gòu)造函數(shù)的次數(shù)Add1333Add2332Add3222Add4221從表中可以看出:(1)Add1函數(shù)的使用效率最低,而Add4函數(shù)的使用效率最高。可見,成員函數(shù)定義的不同往往直接影響程序的執(zhí)行效率,因此成員函數(shù)的參數(shù)和返回值除非得已,應(yīng)盡可能不使用對象。1.結(jié)果分析5.4.1成員函數(shù)的效率(2)考察Add4函數(shù),它的形參只有1個CPoint

對象,那么又怎么能夠?qū)崿F(xiàn)2個對象的加法操作呢?這就是C++類中的this指針在起作用。每當(dāng)一個對象調(diào)用成員函數(shù)時,編譯先將對象的地址賦給this指針,然后調(diào)用成員函數(shù)。這樣,當(dāng)有下列成員函數(shù)調(diào)用時:

pt.Add4(pt2);

它實際上被解釋成:

Add4(&pt,pt2);

只不過,&pt參數(shù)被隱藏了。這樣,當(dāng)執(zhí)行Add4函數(shù)下列代碼時:

voidAdd4(CPointtwo) {

xPos+=two.xPos; yPos+=two.yPos; }就是執(zhí)行這樣的代碼:

voidAdd4(CPoint*this,CPointtwo) { (*this).xPos+=two.xPos; (*this).yPos+=two.yPos; }5.4.1成員函數(shù)的效率因此,由this指針解釋的“Add4(&pt,pt2);”實際執(zhí)行過程如圖5.2所示(圖中的數(shù)字表示執(zhí)行的次序)。pt.Add4(pt2);Add4(&pt,pt2);voidAdd4(CPoint*this,CPointtwo){ (*this).xPos+=two.xPos; (*this).yPos+=two.yPos;}temp←CPoint(pt2)pt.xPos+=temp.xPos;pt.yPos+=temp.yPos;(1)(2)(3)(4)(5)(6)(7)圖5.2pt.Add4(pt2)內(nèi)部執(zhí)行過程5.4.2this指針的實質(zhì)1.this指針的指向從前面的分析可知,當(dāng)類實例化時,即用類定義對象時,則this指針的指向總是對象本身。但在類聲明時,this指針的指向應(yīng)是類本身,所以可以在該類成員函數(shù)中通過this指針來訪問類中的所有成員。簡單地說,當(dāng)類實例化時,this指針的指向?qū)ο笞约?,而在類的聲明時指向類本身。打個比方,this指針就好比你自己一樣,當(dāng)你在屋子里面(類的聲明)時,你只知道“房子”這個概念(類名),而不知道房子是什么樣子,但你可以看到里面的一切(可以通過this指針引用所有成員),所謂“不識廬山真面目,只緣身在此山中”,而當(dāng)你走出屋子外(類的實例),你看到的是一棟具體的房子(this指針指向類的實例)。下面來看一個示例,它是通過this指針用另一個對象直接給對象賦值。5.4.2this指針的實質(zhì)

[例Ex_This]使用this指針#include<iostream>usingnamespacestd;classCPoint{public:

CPoint(intx=0,inty=0) {

xPos=x; yPos=y; }public: voidCopy(CPointone) {

*this=one;

} //直接通過this賦值

voidPrint() {

cout<<"Point("<<xPos<<","<<yPos<<")"<<endl; }private:

int

xPos,yPos;};intmain(){

CPointpt1(10,20),pt2(30,40); pt1.Print(); pt1.Copy(pt2); pt1.Print(); return0;}5.4.2this指針的實質(zhì)類CPoint中,使用this指針的成員函數(shù)是Copy,此時this指針指向類自己,在成員函數(shù)Copy中,由于語句“*this=one”等到對象調(diào)用時才會執(zhí)行,因而當(dāng)在main函數(shù)調(diào)用“pt1.Copy(pt2);”時,this指針指向?qū)ο髉t1,此時“*this=one”是將one的內(nèi)容拷貝到類對象pt1中,這樣就使得pt1的數(shù)據(jù)成員的值等于pt2的數(shù)據(jù)成員的值。因此main函數(shù)中最后的語句“pt1.print();”輸出的結(jié)果就是等于pt2的結(jié)果。程序運行的結(jié)果如下:事實上,當(dāng)成員函數(shù)的形參名與該類的成員變量名同名,則必須用this指針來顯式區(qū)分,例如:

class

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論