《C++程序設(shè)計(jì)教程》課件第3章_第1頁(yè)
《C++程序設(shè)計(jì)教程》課件第3章_第2頁(yè)
《C++程序設(shè)計(jì)教程》課件第3章_第3頁(yè)
《C++程序設(shè)計(jì)教程》課件第3章_第4頁(yè)
《C++程序設(shè)計(jì)教程》課件第3章_第5頁(yè)
已閱讀5頁(yè),還剩136頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

3.1函數(shù)重載

3.2內(nèi)聯(lián)函數(shù)

3.3引用

3.4友元

3.5名空間

本章要點(diǎn)

練習(xí)

3.1.1重載的概念

在C中,在同一個(gè)程序中聲明兩個(gè)同名函數(shù)是一種語(yǔ)法錯(cuò)誤。而在C++中只要函數(shù)命名了不同的參數(shù)集,就允許用同一名字定義多個(gè)函數(shù)。C++的這種能力稱為函數(shù)重載。下面就用C++中提供的重載機(jī)制來(lái)實(shí)現(xiàn)本章開(kāi)始時(shí)提出的求絕對(duì)值問(wèn)題。

【例3-1】演示通過(guò)重載求x的絕對(duì)值。3.1函數(shù)重載通過(guò)重載的方法只用了一個(gè)函數(shù)名Fun,分別實(shí)現(xiàn)了求long、double和int類型數(shù)的絕對(duì)值。重載的優(yōu)點(diǎn)包括:對(duì)于不同的數(shù)據(jù)類型完成類似的操作;對(duì)于函數(shù)名的取名,可以見(jiàn)名知義,消除了在同一操作中使用不同函數(shù)名稱的情況;有助于輕松理解和調(diào)試代碼;使代碼維護(hù)變得更加容易。3.1.2匹配重載函數(shù)的順序

匹配重載函數(shù)是由編譯器完成的。編譯器通過(guò)函數(shù)名和其參數(shù)類型識(shí)別重載函數(shù)。編譯器在識(shí)別時(shí),通過(guò)參數(shù)個(gè)數(shù)、參數(shù)類型和參數(shù)的次序確定被匹配的函數(shù),并對(duì)每一個(gè)函數(shù)的標(biāo)識(shí)符進(jìn)行特別編碼,以便實(shí)現(xiàn)匹配的唯一性。這一過(guò)程有教材稱為“名字改編”或“名字修飾”。在匹配重載函數(shù)時(shí)按優(yōu)先級(jí)進(jìn)行,具體步驟為:先尋找是否有嚴(yán)格匹配(所謂嚴(yán)格匹配,就是同類型的匹配),然后通過(guò)內(nèi)部數(shù)據(jù)轉(zhuǎn)換尋找是否有匹配。

對(duì)于兩個(gè)內(nèi)部數(shù)據(jù),系統(tǒng)能自動(dòng)尋找匹配。如若有l(wèi)ong和double形參,那么0、char和shortint等的實(shí)參,都是經(jīng)內(nèi)部數(shù)據(jù)轉(zhuǎn)換后可匹配的參數(shù)類型。

【例3-2】演示重載函數(shù)的內(nèi)部轉(zhuǎn)換匹配,通過(guò)用戶定義的轉(zhuǎn)換尋找是否有匹配。其中要注意,對(duì)于帶有const修飾的內(nèi)部轉(zhuǎn)換,只適用char*轉(zhuǎn)換為constchar*;對(duì)于其他非指針類型的情況,就認(rèn)為是嚴(yán)格匹配。如在下面的代碼中,由于存在兩個(gè)嚴(yán)格匹配函數(shù)而出錯(cuò),去掉任何一個(gè)都可以。3.1.3對(duì)重載函數(shù)的要求

1.重載函數(shù)具有不同參數(shù)

重載函數(shù)至少在參數(shù)類型、參數(shù)個(gè)數(shù)或者參數(shù)順序上有所不同。C++的函數(shù)如果在參數(shù)類型、參數(shù)個(gè)數(shù)、參數(shù)順序上有所不同,則認(rèn)為是不同的匹配,可以進(jìn)行重載。如果僅僅只有函數(shù)的返回類型不同是不夠的,重載將不能實(shí)現(xiàn)。

在C++中這樣規(guī)定的理由就是要保證對(duì)重載的匹配只是針對(duì)單獨(dú)的運(yùn)算符或函數(shù)調(diào)用,而與調(diào)用環(huán)境無(wú)關(guān)。下面是不合要求的重載函數(shù)的例子。

2.函數(shù)重載要在同一作用域內(nèi)

函數(shù)重載要在同一個(gè)作用域內(nèi)才能實(shí)現(xiàn)。對(duì)于幾個(gè)不同作用域中的函數(shù)是無(wú)法實(shí)現(xiàn)重載的。

【例3-3】函數(shù)重載與作用域的關(guān)系。

#include<iostream.h>

voidFun(intx)

{cout<<"int:"<<x<<endl;}運(yùn)行結(jié)果:

double:100

顯然Fun(100)最好的匹配應(yīng)當(dāng)是Fun(intx),但是Fun(doubley)在main函數(shù)的局部作用域里,所以就優(yōu)先匹配Fun(doublex)。若去掉函數(shù)聲明,則兩個(gè)函數(shù)在同一作用域中,可實(shí)現(xiàn)重載,于是輸出int:100。

3.不要讓重載執(zhí)行不同的功能

重載的目的是:有助于輕松理解和調(diào)試代碼,使代碼維護(hù)變得更加容易,增加可讀性。因此讓重載執(zhí)行不同的功能不是好的編程風(fēng)格。同名函數(shù)應(yīng)該具有相同的功能。3.1.4重載的實(shí)現(xiàn)

重載可以發(fā)生在非成員函數(shù)之間,也可以發(fā)生在同一類的成員函數(shù)之間或構(gòu)造函數(shù)之間??傊?,只要函數(shù)在同一作用域內(nèi),滿足重載的要求就可以進(jìn)行重載。

【例3-4】通過(guò)建一個(gè)表格類來(lái)演示在構(gòu)造函數(shù)之間進(jìn)行重載。

【例3-5】有兩個(gè)類:Student和Tdate類,在這兩個(gè)類中都有兩個(gè)Set,其中一個(gè)是非成員函數(shù)Set。由于作用域的不同,Student類中的Set、Tdate類中的Set和非成員函數(shù)Set之間不能重載。在同一個(gè)類中的兩個(gè)Set是重載函數(shù)。運(yùn)行結(jié)果:

Thedateis2007/08/24

generalfunction

4

上面演示了重載成員函數(shù)的執(zhí)行情況。重載成員函數(shù)既可以用對(duì)象名加分量運(yùn)算符來(lái)訪問(wèn),也可以用指針加分量運(yùn)算符來(lái)訪問(wèn)。由于類名是成員函數(shù)名的一部分,因此一個(gè)類的成員函數(shù)與另一個(gè)類的成員函數(shù)或者普通函數(shù)即使同名,也不能實(shí)現(xiàn)重載。3.1.5重載的二義性

重載無(wú)需人工參與,在重載時(shí)由系統(tǒng)自動(dòng)進(jìn)行參數(shù)轉(zhuǎn)換并尋找匹配。若同時(shí)出現(xiàn)多個(gè)可匹配重載函數(shù),使得系統(tǒng)無(wú)法確定匹配哪個(gè)重載函數(shù),我們將這種現(xiàn)象稱為二義性。

要注意轉(zhuǎn)換的二義性。對(duì)于內(nèi)部自動(dòng)轉(zhuǎn)換是沒(méi)有優(yōu)先級(jí)的。假如實(shí)參是int,而形參同時(shí)有l(wèi)ong和double,int既可以自動(dòng)轉(zhuǎn)換為long,也可以自動(dòng)轉(zhuǎn)換為double,這就出現(xiàn)了二義性。解決方法是進(jìn)行顯式轉(zhuǎn)換。在Fun(1);的調(diào)用中出現(xiàn)了錯(cuò)誤。數(shù)字1可以自動(dòng)轉(zhuǎn)換為double型,也可以自動(dòng)轉(zhuǎn)換為long型,沒(méi)有優(yōu)先級(jí)。若要明確匹配long,可用1L明示。較好的方法是進(jìn)行顯式轉(zhuǎn)換。顯式轉(zhuǎn)換的方法:Fun(long(1));或Fun(double(1));。

函數(shù)可以帶默認(rèn)參數(shù),同樣,重載函數(shù)也可以帶默認(rèn)參數(shù)。有了帶默認(rèn)參數(shù)的函數(shù),在給我們帶來(lái)方便的同時(shí)也帶來(lái)了二義性。如果有一組重載函數(shù),由于它們都帶有默認(rèn)參數(shù),那么即使是有不同參數(shù)個(gè)數(shù)的函數(shù),也有可能出現(xiàn)二義性。函數(shù)調(diào)用需要使用棧,這些工作就需要一些時(shí)間開(kāi)銷。當(dāng)函數(shù)體比較短小,功能簡(jiǎn)單,又需要頻繁調(diào)用時(shí),這種調(diào)用的系統(tǒng)開(kāi)銷相對(duì)而言就較大。如果不用調(diào)用函數(shù)的方式,而直接將代碼寫(xiě)入,使其按順序執(zhí)行,這樣就可以節(jié)省頻繁調(diào)用時(shí)所需的時(shí)間和空間。

3.2內(nèi)聯(lián)函數(shù)在C中常用的方法是用預(yù)處理命令通過(guò)宏定義來(lái)實(shí)現(xiàn)。宏定義是命令,編譯器并不作語(yǔ)法檢查,它可能隱藏著危險(xiǎn),有時(shí)會(huì)得到錯(cuò)誤的結(jié)果。例如,若有#definemultiply(x)x*x,則用y=multiply(5);可以得到y(tǒng)的值為25。若用z=multiply(2+3);,經(jīng)過(guò)宏展開(kāi)為2+3*2+3,z的值為11,這就出錯(cuò)了。解決方法是加上括號(hào):#definemultiply(x)(x)*(x)。在C++中,既要提高程序執(zhí)行的效率,又要減少麻煩,于是引入了內(nèi)聯(lián)函數(shù)。內(nèi)聯(lián)函數(shù)也稱內(nèi)嵌函數(shù),它可以提高程序的運(yùn)行效率,克服宏定義所帶來(lái)的弊端。所謂內(nèi)聯(lián)或內(nèi)嵌,就是將一段小程序經(jīng)編譯后放到程序中使其成為一體。

引入內(nèi)聯(lián)函數(shù),優(yōu)點(diǎn)是安全可靠、可讀性好、效率高,缺點(diǎn)是程序代碼比較長(zhǎng)。3.2.1內(nèi)聯(lián)函數(shù)的實(shí)現(xiàn)

1.一般內(nèi)聯(lián)函數(shù)

內(nèi)聯(lián)函數(shù)既可作為成員函數(shù),也可作為非成員函數(shù)。對(duì)于非成員的內(nèi)聯(lián)函數(shù),我們稱它為一般內(nèi)聯(lián)函數(shù)。例如:

inlineintFun(intx){returnx*x;} //定義內(nèi)聯(lián)函數(shù)Fun

voidmain()

{inty;y=Fun(2+3);?} //y的值為25當(dāng)編譯器在編譯時(shí)每遇到標(biāo)有inline關(guān)鍵字的Fun函數(shù)后,就自動(dòng)為它創(chuàng)建一段代碼,以便每次碰到該函數(shù)的調(diào)用都用相同的一段代碼來(lái)替換,提高效率與可讀性。

對(duì)于main中的y=Fun(2+3);語(yǔ)句,括號(hào)中的參數(shù)會(huì)強(qiáng)制完成正確的運(yùn)算,同時(shí)對(duì)傳遞的參數(shù)將作類型檢查。若出現(xiàn)y=Fun(2.1+3.2f);或者y=Fun(2.1f+3.2f);的調(diào)用,馬上給出警告。因此,內(nèi)聯(lián)函數(shù)既安全又可靠。要說(shuō)明的一點(diǎn)是,內(nèi)聯(lián)函數(shù)不同于其他函數(shù),在編譯時(shí),凡是出現(xiàn)調(diào)用內(nèi)聯(lián)函數(shù)處,總是用一段代碼取代它。本例中內(nèi)聯(lián)函數(shù)的使用y=Fun(2+3);等價(jià)于{intx,y;y=(x=2+3,x*x);},這樣程序運(yùn)行時(shí)就可順序執(zhí)行,免去了函數(shù)調(diào)用的一切步驟,既省略了函數(shù)調(diào)用的時(shí)間開(kāi)銷,又避免了錯(cuò)誤。內(nèi)聯(lián)函數(shù)實(shí)際上是用代碼的空間來(lái)?yè)Q取時(shí)間的。過(guò)多地使用內(nèi)聯(lián)函數(shù)會(huì)增加程序長(zhǎng)度,因此不宜多用。2.內(nèi)聯(lián)成員函數(shù)

在C++中要使某一成員函數(shù)成為內(nèi)聯(lián)函數(shù),有兩種方法實(shí)現(xiàn)。方法一,直接將該函數(shù)的實(shí)現(xiàn)放在類的定義中。對(duì)于只有幾行的函數(shù),可以在類的定義體內(nèi)部定義。如果一個(gè)成員函數(shù)在類定義的內(nèi)部定義,那么該成員函數(shù)將自動(dòng)成為內(nèi)聯(lián)函數(shù)。方法二,用inline聲明。在類定義體外部的成員函數(shù)要想成為內(nèi)聯(lián)函數(shù),則必須明確地使用關(guān)鍵字inline。若要將某函數(shù)聲明為inline(內(nèi)聯(lián)函數(shù)),則可在聲明或定義中加入inline,或者兩者都加入inline也可。

【例3-7】演示內(nèi)聯(lián)函數(shù)的實(shí)現(xiàn)。3.2.2內(nèi)聯(lián)函數(shù)的限制

內(nèi)聯(lián)函數(shù)也是函數(shù),所以要遵循函數(shù)的規(guī)則,如,內(nèi)聯(lián)函數(shù)必須在被調(diào)用之前聲明或定義,且僅聲明一次。

內(nèi)聯(lián)函數(shù)是為提高程序運(yùn)行效率而引入的,所以內(nèi)聯(lián)函數(shù)中不能含有復(fù)雜的結(jié)構(gòu)控制語(yǔ)句。程序員若將含有復(fù)雜的結(jié)構(gòu)控制語(yǔ)句的函數(shù)聲明為內(nèi)聯(lián)函數(shù),編譯器會(huì)自動(dòng)拒絕,編譯時(shí)系統(tǒng)自動(dòng)將該函數(shù)視同普通函數(shù)那樣生成函數(shù)調(diào)用代碼。也就是說(shuō),是否能真正成為內(nèi)聯(lián)函數(shù),由程序員申請(qǐng),編譯器決定。內(nèi)聯(lián)函數(shù)中不能定義任何靜態(tài)變量,不能說(shuō)明數(shù)組。遞歸函數(shù)不能作為內(nèi)聯(lián)函數(shù)。一般來(lái)說(shuō),內(nèi)聯(lián)函數(shù)是1~5行的短函數(shù),若語(yǔ)句較多也不要用內(nèi)聯(lián)函數(shù)。語(yǔ)句較多編譯器不報(bào)錯(cuò),只是自動(dòng)將它視為非內(nèi)聯(lián)函數(shù)。3.3.1引用的概念

引用的概念就是給變量或?qū)ο笕∫粋€(gè)別名。我們現(xiàn)實(shí)生活中的人可以有別名,程序設(shè)計(jì)中的對(duì)象也可以有別名。在C++中給變量或?qū)ο笕∫粋€(gè)別名的方法稱為引用。建立引用的方法:

類型&別名=目標(biāo)名;

例如:intx;int&n=x;先定義了一個(gè)整型變量x,接著給變量x取了一個(gè)別名n。

引用不是值,不占存儲(chǔ)空間。聲明引用時(shí),目標(biāo)的存儲(chǔ)狀態(tài)不會(huì)改變。因此引用只有聲明沒(méi)有定義。3.3引用3.3.2引用的操作

由于引用僅僅是對(duì)象的別名或化身,因此引用必須在聲明時(shí)初始化。這意味著從引用誕生起,它就是其他目標(biāo)的別名,為別名而存在。從中也就告訴我們,若引用一個(gè)不存在的對(duì)象將是一個(gè)錯(cuò)誤。

【例3-8】通過(guò)本例體會(huì)引用是別名,別名的行為就是目標(biāo)的行為。#include<iostream.h>

voidmain()

{intx=3;int&a=x;

cout<<“x=”<<x<<“a=”<<a<<endl;

//引用作為目標(biāo)的別名而使用

a=8;cout<<“x=”<<x<<“a=”<<a<<endl;

//對(duì)引用的改動(dòng)就是對(duì)目標(biāo)的改動(dòng)

cout<<“&x=”<<&x<<“\t”<<“&a=”<<&a<<endl;

//引用的地址就是目標(biāo)的地址

}

運(yùn)行結(jié)果顯示x和a的值相同,地址也相同。3.3.3引用的利弊

也許我們正在思考這樣一個(gè)問(wèn)題,好端端地為什么要多出一個(gè)引用,一個(gè)別名,別名做的事也算到原目標(biāo)名的帳上,是否有點(diǎn)多此一舉。

1.引用的優(yōu)點(diǎn)

在C中,函數(shù)調(diào)用都是傳值調(diào)用,函數(shù)不能訪問(wèn)調(diào)用程序中的原始變量,而只能訪問(wèn)為它而創(chuàng)建的副本。由于引用是某一對(duì)象的別名,因此在函數(shù)調(diào)用中,引用傳遞的就是原來(lái)的變量或?qū)ο?,而不是函?shù)作用域內(nèi)建立的變量或?qū)ο蟾北?。引用作為參?shù)傳遞時(shí)具有指針作為函數(shù)參數(shù)的效果。下面我們將對(duì)C++中引入引用的一些優(yōu)點(diǎn)作一介紹。

(1)引用具有指針的威力。引用傳遞的是原來(lái)的變量或?qū)ο?,所以說(shuō)引用具有指針的威力。引用具有傳值方式函數(shù)調(diào)用語(yǔ)法的簡(jiǎn)單性與可讀性,但威力卻比傳值方式強(qiáng)。

(2)引用可以避免對(duì)象拷貝。在對(duì)象的傳遞中,為避免拷貝對(duì)象的開(kāi)銷,可用引用的方式來(lái)傳遞對(duì)象。因?yàn)樗鼉H是一個(gè)別名,不是另一個(gè)對(duì)象,不占有空間。因此引用作參數(shù)既節(jié)省空間,又節(jié)約時(shí)間。它隨目標(biāo)而產(chǎn)生,隨目標(biāo)的消亡而消亡。

(3)引用可以避免原始數(shù)據(jù)被修改。為了防止調(diào)用函數(shù)修改調(diào)用者的原始數(shù)據(jù),可以用傳遞常量引用的方式傳遞這些數(shù)據(jù)。在C++中通常用指針傳遞要修改的參數(shù),用引用常量的方法傳遞不要修改的參數(shù)。要想說(shuō)明對(duì)常量的引用,只要把const限定符放在參數(shù)聲明的類型說(shuō)明前即可。

【例3-9】演示引用的威力。#include<iostream.h>

voidmain()

{voidswap(int&,int&);

intx=5,y=6;

cout<<"beforeswap:\t"<<"x="<<x<<""<<"y="<<y<<endl;

swap(x,y);

cout<<"afterswap:\t"<<"x="<<x<<""<<"y="<<y<<endl;

}voidswap(int&u,int&v)

{inttemp;

temp=u;u=v;v=temp;

}

運(yùn)行結(jié)果:

beforeswap: x=5y=6

afterswap: x=6y=5從運(yùn)行結(jié)果可知,x、y的值被交換了。在voidswap(int&u,int&v)中用引用作函數(shù)參數(shù),這就意味著只要有參數(shù)傳過(guò)來(lái),它就是該參數(shù)的別名。因?yàn)閡是x的別名,v是y的別名,對(duì)u、v的改變就是對(duì)x、y的改變。

2.引用存在的問(wèn)題

任何事物都是一分為二的。在引用給我們帶來(lái)方便的同時(shí)也帶來(lái)了新的問(wèn)題。下面就對(duì)可能出現(xiàn)的錯(cuò)誤進(jìn)行分析,以便在采用引用時(shí)權(quán)衡利弊。

(1)可能隱藏錯(cuò)誤。在函數(shù)調(diào)用時(shí),我們?cè)f(shuō)過(guò)是拷貝調(diào)用,不用擔(dān)心參數(shù)被修改的問(wèn)題。然而有了引用后問(wèn)題就出來(lái)了?,F(xiàn)通過(guò)下面的代碼來(lái)體會(huì)一下危險(xiǎn)性。

intx=6;inty=8;

swap(x,y);對(duì)于swap(x,y);調(diào)用,沒(méi)有看到被調(diào)函數(shù)原型之前,就不能確定實(shí)參x和y是否會(huì)在被調(diào)函數(shù)中被修改。請(qǐng)看下面的兩個(gè)函數(shù)。

若被調(diào)函數(shù)是:

voidswap(intu,intv){intt=u;u=v;v=t;}

在函數(shù)調(diào)用時(shí),通過(guò)參數(shù)拷貝,在swap中沒(méi)有能力改變實(shí)參x和y的值,即x和y不會(huì)被交換。

若被調(diào)函數(shù)是:

voidswap(int&u,int&v) //x和y被交換

{intt=u;u=v;v=t;}在被調(diào)函數(shù)中的參數(shù)是引用,一旦接收到實(shí)參x和y,形參u和v就分別成為x和y的別名。那么對(duì)別名的改變就是對(duì)目標(biāo)名的改變,實(shí)參x和y的值就可以被改變。

綜合上面的分析可知引用的危險(xiǎn)性,即在被調(diào)函數(shù)中可能隱藏著主調(diào)函數(shù)中參數(shù)被修改的可能性。

(2)可能引起編譯錯(cuò)誤。使用引用后,重載函數(shù)時(shí)可能引起編譯錯(cuò)誤。從上面的分析可知,同一函數(shù)swap的調(diào)用有兩種可能的匹配方式,若兩個(gè)被調(diào)函數(shù)同時(shí)出現(xiàn),系統(tǒng)就不知道該匹配哪一個(gè),這就引起了編譯錯(cuò)誤。voidswap(intx,inty){/*………*/}

voidswap(int&a,int&b){/*………*/}

voidmain()

{intx=6;inty=8;

swap(x,y);

}

對(duì)于swap(x,y)的函數(shù)調(diào)用,上面兩個(gè)swap函數(shù)的參數(shù)雖然一個(gè)是變量,一個(gè)是引用,但都是整型參數(shù),是同一類型。由于不能從函數(shù)調(diào)用中判斷是值傳遞還是引用傳遞,因此無(wú)法確定swap(x,y);匹配哪一個(gè)函數(shù)。3.3.4引用規(guī)則

在建立引用時(shí),是對(duì)同類數(shù)據(jù)類型的變量或?qū)ο蟮囊?,不是?duì)數(shù)據(jù)類型的引用。若一個(gè)變量聲明為T(mén)ype&,引用時(shí)它必須用Type類型的變量或?qū)ο蟪跏蓟?,或用能轉(zhuǎn)換成Type類型的(變量或)對(duì)象初始化。例如,若有inta[8];int&b=a;則出錯(cuò),因?yàn)閷?duì)整型的引用,只能用整型變量初始化,不能用數(shù)組名。數(shù)組名是地址,是常量。

(1)在引用變量或?qū)ο髸r(shí)可以引用一個(gè)相同數(shù)據(jù)類型的變量或?qū)ο?。例如:doublex,temp;floaty;

double&t=temp; //ok

double&t=x; //error,引用不能重名

double&z=y;

//error,引用了不同類型的變量

inta;int*&q=&a; //error,不能取一個(gè)地址的別名

float&w=float; //error,不能對(duì)類型引用

float&v=8.8f; //error,變量不能作為數(shù)據(jù)的別名

若是對(duì)常量的引用,則可以用constfloat&v=8.8f,即v就是8.8的別名。

(2)在引用指針變量時(shí)可以引用一個(gè)同類型的指針變量。例如:

int*p;inta;p=&a;

int*&q=p; //ok

即使p還沒(méi)有指向也可以引用。例如:

int*p;int*&q=p; //ok

該句的語(yǔ)義是將int*的引用q初始化為p。雖然此時(shí)p還無(wú)指向,但也是引用的初始化。

inta=8;q=&a; //ok,對(duì)于指針變量的引用,可改變指向

由于q是p的別名,因此它們是同一個(gè)指針,現(xiàn)在q指向a,當(dāng)然p也就指向a。

(3)不能建立引用數(shù)組。數(shù)組是某個(gè)數(shù)據(jù)類型元素的集合,數(shù)組名表示該集合空間的起始地址,而不是某個(gè)數(shù)據(jù)類型的變量或?qū)ο蟆H绻衖nta[8];int&b[8]=a;,則出錯(cuò)。

(4)若將引用作為類的數(shù)據(jù)成員,則必須初始化。例如:3.3.5指針和引用的區(qū)別

指針和引用有相同點(diǎn),同時(shí)也存在著差別,主要表現(xiàn)在如下幾個(gè)方面。第一,操作方式不同。指針是間接訪問(wèn),而引用是直接訪問(wèn)。例如:int*p,a;p=&a;*p=8;通過(guò)p間接訪問(wèn)a空間。intb;int&q=b;q=9;由q直接訪問(wèn)b空間。第二,指針本身是一個(gè)變量,可以不初試化,而引用是別名,必須初試化;指針可以再指向其他變量,而引用一旦確立,就不能再作為其他變量的別名。3.4.1友元函數(shù)

在C++中提供了一個(gè)稱為友元的函數(shù),該函數(shù)就是類的朋友。友元函數(shù)不是類的成員函數(shù),而是普通的C++函數(shù),但它可以訪問(wèn)類的保護(hù)或私有成員,方便編程,提高效率。

一個(gè)普通函數(shù)可以是某類的友元,一個(gè)類的成員函數(shù)也可以是另一個(gè)類的友元,該函數(shù)就稱為友元函數(shù)。3.4友元

1.友元函數(shù)聲明

友元要在類中聲明。因?yàn)橛言皇穷惖某蓡T,所以它不受其所在類的聲明區(qū)域的影響,聲明時(shí)既可以放在public區(qū),也可以放在private區(qū)或protected區(qū),結(jié)果是一樣的。友元函數(shù)的定義必須放在類的外部,可以與該類成員函數(shù)的定義放在一起。

2.應(yīng)用場(chǎng)合

普通函數(shù)需要訪問(wèn)類的保護(hù)或私有成員時(shí),若沒(méi)有友元機(jī)制,則只能將類的數(shù)據(jù)成員聲明為公有的,那么任何函數(shù)都可以無(wú)約束地訪問(wèn)它。友元函數(shù)就是為了能在類之外訪問(wèn)類的保護(hù)或私有成員,而與類建立朋友關(guān)系的函數(shù)。一般在下列三種情況下要用到友元函數(shù):

(1)要通過(guò)重載運(yùn)算符實(shí)現(xiàn)某些類型對(duì)象的運(yùn)算(將在第5章中介紹)。

(2)要簡(jiǎn)化創(chuàng)建某些類型的I/O函數(shù)的過(guò)程(將在第8章中介紹)。

(3)要將某些類型的特征進(jìn)行互相關(guān)聯(lián)或比較時(shí)。

3.使用方法

首先進(jìn)行友元函數(shù)聲明,然后在該類之外完成友元函數(shù)的實(shí)現(xiàn)。聲明方法是在類中按聲明一個(gè)普通函數(shù)的方法聲明函數(shù),并在該函數(shù)的類型前標(biāo)上關(guān)鍵字friend,這時(shí)函數(shù)就成了該類的友元。在友元函數(shù)的實(shí)現(xiàn)部分,函數(shù)頭不再需要加關(guān)鍵字friend,在函數(shù)體內(nèi)完成所需功能。

【例3-10】若有凳子和桌子類,現(xiàn)要求比較顏色是否一樣。本例中定義有兩個(gè)全局對(duì)象,用來(lái)演示普通函數(shù)作為類的友元是如何訪問(wèn)對(duì)象的保護(hù)成員的。運(yùn)行結(jié)果:

DeskandBencharedifferentcolor

在本例的兩個(gè)類中,友元函數(shù)的聲明位置不同,效果是一樣的。本例實(shí)現(xiàn)了在一個(gè)普通函數(shù)中,將兩個(gè)類的顏色特征進(jìn)行相互比較的功能。將普通函數(shù)Check同時(shí)聲明為Desk和Bench類的友元,那么在Check中就可以訪問(wèn)這兩個(gè)類的所有成員。訪問(wèn)方法如同訪問(wèn)公有成員一樣,即對(duì)象名.成員。

【例3-11】教師類中的成員函數(shù)Check和Display是學(xué)生類的友元函數(shù),它們能訪問(wèn)學(xué)生的學(xué)號(hào)和課程,而教師類中的Test函數(shù)無(wú)此特權(quán)。通過(guò)本例演示一個(gè)類的成員函數(shù)作為另一個(gè)類的友元函數(shù)的實(shí)現(xiàn)方法。

#include<iostream.h>

classStudent; //Teacher用到Student類作參數(shù),故作聲明

classTeacher

{public:運(yùn)行結(jié)果:

num=203course=4.5

本例演示了聲明和定義友元函數(shù)的方法。因?yàn)榻處燁愔杏谐蓡T函數(shù)是學(xué)生類的友元函數(shù),所以必須將Teacher類的定義放在Student類的定義之前。

在本例中又有學(xué)生類的引用作函數(shù)參數(shù),如Teacher::Check(Student&),因此就要在教師類的定義前加上學(xué)生類的聲明。聲明方法是:關(guān)鍵字class加上類名,如上面的classStudent;所示。

【例3-12】該例的描述中,將Teacher類的成員函數(shù)Fun聲明為Student友元,又將普通函數(shù)Display和Show聲明為Student友元。

#include<iostream.h>

classStudent; //類聲明

classTeacher

{public:

voidassignGreads(int);

voidFun(Student&a);//以Student類的引用作為形參

private:

intnoofstudent;

};運(yùn)行結(jié)果:

score=78

Newscore=88

Newscoreis:88

Thescoreis:0

該例同時(shí)演示了成員函數(shù)和普通函數(shù)作為友元函數(shù),訪問(wèn)類中保護(hù)或私有成員的方法。從中也進(jìn)一步得知友元函數(shù)的使用要慎重,因?yàn)樗鼤?huì)破壞類的封裝性。

4.關(guān)于友元的說(shuō)明

在聲明A類的成員函數(shù)為B類的友元時(shí),要將A類的定義放在B類的定義之前。若A類的成員函數(shù)的參數(shù)中有C類的類型,則在A類的定義之前加上C類的聲明或C類的定義,即要實(shí)現(xiàn)可知性。友元不是成員函數(shù),它是類的朋友。既然是朋友,它就能訪問(wèn)類的全部成員。友元是單向的。如僅僅A是B的友元,則A能訪問(wèn)B類的全部成員,而B(niǎo)卻不能訪問(wèn)A類的成員。即友元關(guān)系是“給予”,而不是“索取”。

友元機(jī)制在給我們帶來(lái)好處的同時(shí)也產(chǎn)生了新的不足。正因?yàn)樗梢栽L問(wèn)類的保護(hù)或私有成員,而破壞了類的封裝性。因此我們說(shuō),友元破壞了類的封裝,在使用它時(shí),要權(quán)衡利弊。3.4.2友元類

可以將整個(gè)類聲明為另一個(gè)類的友元,該類就稱為友元類或友類。友類中的每個(gè)成員函數(shù)都可以訪問(wèn)另一類中的保護(hù)或私有成員,這就減少了將所有成員函數(shù)都聲明為友元的麻煩。

【例3-13】有Leader、Teacher和Student三個(gè)類,要求實(shí)現(xiàn)Leader中的object是Teacher的友元函數(shù),可訪問(wèn)Teacher,Teacher是Student類的友類。運(yùn)行結(jié)果:

score=78 //調(diào)用Student類的成員函數(shù)后得

Newscore=88 //調(diào)用Teacher類的成員函數(shù)后得

Numberofstudent35 //調(diào)用Leader類的成員函數(shù)后得

從運(yùn)行結(jié)果來(lái)看,該例實(shí)現(xiàn)了有效訪問(wèn)。如最后一行的輸出結(jié)果是調(diào)用Leader類的成員函數(shù),在該成員函數(shù)中訪問(wèn)了Teacher類中的private成員noofstudent。

在上面的例子中,Teacher類是Student類的友類,Teacher類中的所有成員函數(shù)都可以訪問(wèn)Student類中的私有或保護(hù)成員;反之,Student類中的成員函數(shù)卻不可以訪問(wèn)Teacher類中的私有或保護(hù)成員。3.4.3互為友類

若兩個(gè)類之間需要相互訪問(wèn),可以聲明互為友類。這樣兩個(gè)類中的所有成員函數(shù)就都可以互訪。這如同我們生活中的從個(gè)人朋友關(guān)系,發(fā)展到家庭之間的友誼而相互友好往來(lái)一樣。

【例3-14】教師類與學(xué)生類互為友類。教師可修改學(xué)生的成績(jī),也可調(diào)整學(xué)時(shí)數(shù)。學(xué)生也可訪問(wèn)在校生總數(shù)。運(yùn)行結(jié)果:

15000

score=87

hours=110

Numberofstudent:150003.5.1概念與作用

在C++中,可以將一些對(duì)象名限制在以某一標(biāo)識(shí)符命名的空間內(nèi),該被命名的空間稱為名空間。使用名空間是為了解決代碼名的重復(fù)和排斥問(wèn)題。名空間機(jī)制允許我們封裝名字,否則名字可能會(huì)污染全局名空間(pollutetheglobalnamespace)。一般來(lái)說(shuō),當(dāng)程序員希望自己的代碼被外部軟件開(kāi)發(fā)部門(mén)使用時(shí),才使用名空間。C++提供了一種機(jī)制,可以把相關(guān)數(shù)據(jù)、函數(shù)等組織到一個(gè)獨(dú)立的名空間里。3.5名空間3.5.2實(shí)現(xiàn)方法

名空間的實(shí)現(xiàn)方法是:

namespace標(biāo)識(shí)符{所有被封裝在以該標(biāo)識(shí)符命名的名空間內(nèi)的名字聲明}

例如,模塊My_Newspace和You_Newspace的用戶界面可以用下面的方法聲明和使用:

//My_Newspace.h

//頭文件名

#include<iostream.h>

namespaceMy_Newspace

{classArray關(guān)鍵字namespace后面的名字My_Newspace標(biāo)識(shí)了一個(gè)名空間,它獨(dú)立于全局名空間,我們可以在里面放一些希望在函數(shù)或類之外聲明(定義)的實(shí)體。名空間不改變其中聲明的意義,只改變它們的可見(jiàn)性。

若要定義一個(gè)對(duì)象,可以用:My_Newspace::Arrayma;You_Newspace::Arrayia;。這樣一來(lái),ma是我公司類的對(duì)象,ia是你公司類的對(duì)象。這樣就避免了都使用相同名字Array而引發(fā)的名字沖突。

程序員希望訪問(wèn)名空間內(nèi)聲明的名字時(shí)不加限定修飾符,這時(shí)可以使用using指示符,使名空間內(nèi)的所有聲明都可見(jiàn)。

using與namespace都是關(guān)鍵字。usingnamespaceMy_Newspace;的語(yǔ)義是將模塊My_Newspace中的所有名字統(tǒng)統(tǒng)放入全局名空間內(nèi)。也就是說(shuō),所有在該名空間里聲明的名字都成為本文件的全局名字。其中要注意兩個(gè)問(wèn)題:第一,被使用的名空間必須已經(jīng)被聲明了,否則會(huì)引起編譯錯(cuò)誤;第二,不要再聲明與已可見(jiàn)名字相同的全局變量。為避免沖突,using聲明還可以實(shí)現(xiàn)有選擇的可見(jiàn)性。3.5.3嵌套名空間

用戶聲明的名空間允許嵌套,從而成為嵌套名空間。例如:

namespaceMy_NameA

{constdoublepi=3.1416;

namespaceMy_NameB若要聲明類名字,可以用:My_NameA::My_NameB::Array。若要聲明類成員名字,可以用:voidMy_NameA::My_NameB::Array::Set。3.5.4std名空間

為了防止標(biāo)準(zhǔn)C++庫(kù)的組件污染用戶的全局名空間,所有C++庫(kù)的組件都封裝在一個(gè)被稱為std的名空間內(nèi)。使用時(shí)可以先用#include<iostream>,再用using指示符,使得C++庫(kù)內(nèi)在名空間std中聲明的組件對(duì)于我們的程序可見(jiàn)。在本例中endl已可見(jiàn),可以直接使用,而cout并未可見(jiàn),所以要加上空間名。若去掉usingstd::endl;聲明,要實(shí)現(xiàn)同樣的效果就得聲明如下:

#include<iostream>

voidmain()

{std::cout<<“namespace”<<std::endl;

}本例中用到了#include<iostream>。<iostream.h>與<iostream>的區(qū)別是:iostream.h是早期C++中的使用方式,這些老式的頭文件只是將標(biāo)準(zhǔn)庫(kù)定義的功能引入全局名空間,而不是把名字引入名空間std。若用戶的系統(tǒng)還不支持新方式,仍可以用老方式,只要加上?.h,同時(shí)去掉對(duì)名空間std的使用即可。3.5.5匿名名空間

在C++中可以使用不給出名字的名空間,使得在該空間內(nèi)聲明的變量或函數(shù),在其他文件中不可以訪問(wèn)。例如:

//頭文件,fun.h

voidShow();

doubleFun(intc);

//實(shí)現(xiàn)文件,fun.cpp

#include“fun.h”

#include<iostream.h>intk; //定義該文件中的全局變量

namespace //匿名名空間

{doublen; //成員只能在本文件中使用,或稱文件

數(shù)據(jù)

intm=0; //文件數(shù)據(jù)

voidSet(){n=8;} //文件函數(shù)

}

voidShow(){cout<<k<<endl;}//全局函數(shù)

doubleFun(intc)

{Set(); //它只能在本文件中使用

returnn+c;對(duì)于某一文件的全局變量,在另一文件中只要對(duì)其進(jìn)行擴(kuò)展聲明,便可使用該變量。而若將某名字放在未命名的名空間內(nèi),那么其他文件就不能訪問(wèn)它了。上例中,函數(shù)Fun()在未命名的名空間內(nèi),它只能在本文件中被訪問(wèn),不能被其他文件訪問(wèn)。將某一名字的使用范圍限制在一個(gè)文件中,優(yōu)點(diǎn)是其他文件就可以再一次使用這個(gè)相同的名字,兩個(gè)文件相互不干擾?!?重載適用于在不同類型的函數(shù)上作不同運(yùn)算而用相同名的情況。

●?C++的函數(shù)如果在參數(shù)類型、參數(shù)個(gè)數(shù)、參數(shù)順序上有所不同,則認(rèn)為是不同的匹配,可以進(jìn)行重載。

●?重載的目的是:更方便理解和調(diào)試代碼,使代碼維護(hù)變得更加容易,增加可讀性。

●?不要讓重載執(zhí)行不同的功能,同名函數(shù)應(yīng)該具有相同的功能。

●?函數(shù)重載時(shí)要考慮到實(shí)現(xiàn)匹配的唯一性。本章要點(diǎn)●?內(nèi)聯(lián)函數(shù)主要用來(lái)提高程序的運(yùn)行效率,克服宏定義使用#define所帶來(lái)的弊端。

●?將函數(shù)的實(shí)現(xiàn)放在類的定義中,那么該成員函數(shù)將自動(dòng)成為內(nèi)聯(lián)函數(shù)。

●?內(nèi)聯(lián)函數(shù)實(shí)際上是用空間換取時(shí)間。

●?內(nèi)聯(lián)函數(shù)是1~5行的小函數(shù),若語(yǔ)句較多就不要用內(nèi)聯(lián)函數(shù)。

●?在C++中給變量或?qū)ο笕∫粋€(gè)別名的方法稱為引用。

●?引用不是值,不占用存儲(chǔ)空間,因此引用只有聲明沒(méi)有定義。●?在建立引用時(shí),只能對(duì)同類數(shù)據(jù)類型的變量或?qū)ο筮M(jìn)行引用。

●?引用傳遞的是原來(lái)的變量或?qū)ο螅哉f(shuō)引用具有指針的作用。

●引用與指針有很大的差別,指針是個(gè)變量,可以把它再指向其他地址,然而建立引用時(shí)必須初始化且不能再把它取為另一對(duì)象的別名。

●?傳遞引用不生成副本,返回引用時(shí)也不生成值的副本,可見(jiàn)引用對(duì)空間無(wú)要求。

●?引用可能隱藏錯(cuò)誤,在使用中要引起注意。

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論