版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
(一)C++與C語言的區(qū)別上
(一)C++與C語言的區(qū)別下
(二)類的設(shè)計(jì),構(gòu)造函數(shù)和析構(gòu)函數(shù)
(三)類的轉(zhuǎn)換
(四)私有數(shù)據(jù)成員和友元
(五)析構(gòu)函數(shù)和this指針
(六)類對(duì)象數(shù)組和靜態(tài)成員
(七)類和堆
(八)類的其他幾點(diǎn)問題
(九)重載運(yùn)算符
(十)重載雙目運(yùn)算符
注明:以下及其后續(xù)內(nèi)容部分摘自《StandardC++Bible》,所有程序代碼都在VisualStdi。6.0
中編譯運(yùn)行,操作系統(tǒng)為WinXP。本文不涉及VC6.0開發(fā)工具的使用,只講解C++語法知
識(shí)。
C++和C的共同部分就不講解了(如常量和變量,循環(huán)語句和循環(huán)控制,數(shù)組和指針等,
這里面的一些區(qū)別會(huì)在本節(jié)和下節(jié)介紹一下),具體可看精華區(qū),新手上路,C語言入門,
本文著重介紹C++的特點(diǎn),如類、繼承和多重繼承、運(yùn)算符重載、類模板、C++標(biāo)準(zhǔn)庫(kù)、模
板庫(kù)、等等。
—、C++概述
(一)發(fā)展歷史
1980年,BjarneStroustrup博士開始著手創(chuàng)建一種模擬語言,能夠具有面向?qū)ο蟮某绦蛟O(shè)計(jì)
特色。在當(dāng)時(shí),面向?qū)ο缶幊踢€是一個(gè)比較新的理念,Stroustrup博士并不是從頭開始設(shè)計(jì)
新語言,而是在C語言的基礎(chǔ)上進(jìn)行創(chuàng)建。這就是C++語言。
1985年,C++開始在外面慢慢流行。經(jīng)過多年的發(fā)展,C++已經(jīng)有了多個(gè)版本。為次,ANSI
和ISO的聯(lián)合委員會(huì)于1989年著手為C++制定標(biāo)準(zhǔn)。1994年2月,該委員會(huì)出版了第一份
非正式草案,1998年正式推出了C++的國(guó)際標(biāo)準(zhǔn)。
(二)C和C++
C++是C的超集,也可以說C是C++的子集,因?yàn)镃先出現(xiàn)。按常理說,C++編譯器能夠
編譯任何C程序,但是C和C++還是有一些小差別。
例如C++增加了C不具有的關(guān)鍵字。這些關(guān)鍵字能作為函數(shù)和變量的標(biāo)識(shí)符在C程序中使
用,盡管C++包含了所有的C,但顯然沒有任何C++編譯器能編譯這樣的C程序。
C程序員可以省略函數(shù)原型,而C++不可以,一個(gè)不帶參數(shù)的C函數(shù)原型必須把void寫出
來。而C++可以使用空參數(shù)列表。
C++中new和delete是對(duì)內(nèi)存分配的運(yùn)算符,取代了C中的malloc和free。
標(biāo)準(zhǔn)C++中的字符串類取代了C標(biāo)準(zhǔn)C函數(shù)庫(kù)頭文件中的字符數(shù)組處理函數(shù)。
C++中用來做控制態(tài)輸入輸出的iostream類庫(kù)替代了標(biāo)準(zhǔn)C中的stdio函數(shù)庫(kù)。
C++中的try/catch/throw異常處理機(jī)制取代了標(biāo)準(zhǔn)C中的setjmp。和longjmp()函數(shù)。
二、關(guān)鍵字和變量
C++相對(duì)與C增加了一些關(guān)鍵字,如下:
typenamebooldynamic_castmutablenamespace
static_castusingcatchexplicitnew
virtualoperatorfalseprivatetemplate
volatileconstprotectedthiswchar_t
const_castpublicthrowfriendtrue
reinterpret_casttry
bitorxor_eand_eqcomplor_eq
not_eqbitand
在C++中還增加了bool型變量和wchar_t型變量:
布爾型變量是有兩種邏輯狀態(tài)的變量,它包含兩個(gè)值:真和假。如果在表達(dá)式中使用了布爾
型變量,那么將根據(jù)變量值的真假而賦予整型值1或0。要把一個(gè)整型變量轉(zhuǎn)換成布爾型變
量,如果整型值為0,則其布爾型值為假;反之如果整型值為非0,則其布爾型值為真。布
兒型變量在運(yùn)行時(shí)通常用做標(biāo)志,比如進(jìn)行邏輯測(cè)試以改變程序流程。
#includeiostream.h
intmain()
(
boolflag;
flag=true;
if(flag)cout<return0;
)
C++中還包括wchajt數(shù)據(jù)類型,wchar」也是字符類型,但是是那些寬度超過8位的數(shù)據(jù)類
型。許多外文字符集所含的數(shù)目超過256個(gè),char字符類型無法完全囊括。wchar」數(shù)據(jù)類
型一般為16位。
標(biāo)準(zhǔn)C++的iostream類庫(kù)中包括了可以支持寬字符的類和對(duì)象。用wout替代cout即可。
#includeiostream,h
intmain()
(
wchar_twc;
wc=,b,;
wout<wc='y';
wout<wc='e';
wout<return0;
)
說明一?下:某些編譯器無法編譯該程序(不支持該數(shù)據(jù)類型)。
三、強(qiáng)制類型轉(zhuǎn)換
有時(shí)候,根據(jù)表達(dá)式的需要,某個(gè)數(shù)據(jù)需要被當(dāng)成另外的數(shù)據(jù)類型來處理,這時(shí),就需要強(qiáng)
制編譯器把變量或常數(shù)由聲明時(shí)的類型轉(zhuǎn)換成需要的類型。為此,就要使用強(qiáng)制類型轉(zhuǎn)換說
明,格式如下:
int*iptr=(int*)&table;
表達(dá)式的前綴(int*)就是傳統(tǒng)C風(fēng)格的強(qiáng)制類型轉(zhuǎn)換說明(typecast),又可稱為強(qiáng)制轉(zhuǎn)換說明
(cast)。強(qiáng)制轉(zhuǎn)換說明告訴編譯器把表達(dá)式轉(zhuǎn)換成指定的類型。有些情況下強(qiáng)制轉(zhuǎn)換是禁用
的,例如不能把?個(gè)結(jié)構(gòu)類型轉(zhuǎn)換成其他任何類型。數(shù)字類型和數(shù)字類型、指針和指針之間
可以相互轉(zhuǎn)換。當(dāng)然,數(shù)字類型和指針類型也可以相互轉(zhuǎn)換,但通常認(rèn)為這樣做是不安全而
且也是沒必要的。強(qiáng)制類型轉(zhuǎn)換可以避免編譯器的警告。
longintel=123;
shorti=(int)el;
floatm=34.56;
inti=(int)m;
上面兩個(gè)都是C風(fēng)格的強(qiáng)制類型轉(zhuǎn)換,C++還增加了一種轉(zhuǎn)換方式,比較一下上面和下面這
個(gè)書寫方式的不同:
longintel=123;
shorti=int(el);
floatm=34.56;
inti=int(m);
使用強(qiáng)制類型轉(zhuǎn)換的最大好處就是:禁止編譯器對(duì)你故意去做的事發(fā)出警告。但是,利用強(qiáng)
制類型轉(zhuǎn)換說明使得編譯器的類型檢查機(jī)制失效,這不是明智的選擇。通常,是不提倡進(jìn)行
強(qiáng)制類型轉(zhuǎn)換的。除非不可避免,如要調(diào)用maHoc()函數(shù)時(shí)要用的void型指針轉(zhuǎn)換成指定類
型指針。
四、標(biāo)準(zhǔn)輸入輸出流
在C語言中,輸入輸出是使用語句scanf()和printf()來實(shí)現(xiàn)的,而C++中是使用類來實(shí)現(xiàn)的。
#includeiostream.h
main()〃C++中main()函數(shù)默認(rèn)為int型,而C語言中默認(rèn)為void型。
(
inta;
cout<cin?a;/*輸入一個(gè)數(shù)值*/
cout<return0;
)
cin,cout,endl對(duì)象,他們本身并不是C++語言的組成部分。雖然他們已經(jīng)是ANSI標(biāo)準(zhǔn)C++
中被定義,但是他們不是語言的內(nèi)在組成部分。在C++中不提供內(nèi)在的輸入輸出運(yùn)算符,這
與其他語言是不同的。輸入和輸出是通過C++類來實(shí)現(xiàn)的,cin和cout是這些類的實(shí)例,他
們是在C++語言的外部實(shí)現(xiàn)。
在C++語言中,有了一種新的注釋方法,就是'〃',在該行〃后的所有說明都被編譯器認(rèn)為
是注釋,這種注釋不能換行。C++中仍然保留了傳統(tǒng)C語言的注釋風(fēng)格/*……*/。
C++也可采用格式化輸出的方法:
#includeiostream.h
intmain()
(
inta;
coutccin?a;六、函數(shù)重載
在C++中,允許有相同的函數(shù)名,不過它們的參數(shù)類型不能完全相同,這樣這些函數(shù)就可以
相互區(qū)別開來。而這在C語言中是不允許的。
1.參數(shù)個(gè)數(shù)不同
#includeiostream.h
voida(int,int);
voida(int);
intmain()
(
a(5);
a(6,7);
return0;
)
voida(inti)
(
cout<}
voida(j)
(
cout<}
2.參數(shù)格式不同
#includeiostream.h
voida(int,int);
voida(int,float);
intmain()
(
a(5,6);
a(6,7.0);
return0;
)
voida(inti,intj)
(
cout<}
voida(inti,floatj)
(
cout<}
七、變量作用域
C++語言中,允許變量定義語句在程序中的任何地方,只要在是使用它之前就可以;而C語
言中,必須要在函數(shù)開頭部分。而且C++允許重復(fù)定義變量,C語言也是做不到這一點(diǎn)的。
看下面的程序:
#includeiostream.h
inta;
intmain()
(
cin?a;
for(inti=l;i<=10;i++)//C語言中,不允許在這里定義變量
(
staticinta=0;〃C語言中,同一函數(shù)塊,不允許有同名變量
a+=i;
cout?::a?<}
return0;
)
八、new和delete運(yùn)算符
在C++語言中,仍然支持malloc()和free。來分配和釋放內(nèi)存,同時(shí)增加了new和delete來
管理內(nèi)存。
1.為固定大小的數(shù)組分配內(nèi)存
#includeiostream.h
intmain()
(
int"birthday二newint[3];
birthday[0]=6;
birthdayf1]=24;
birthday⑵=1940;
cout<<delete[]birthday;〃注意這兒
return0;
)
在刪除數(shù)組時(shí),delete運(yùn)算符后要有一對(duì)方括號(hào)。
2.為動(dòng)態(tài)數(shù)組分配內(nèi)存
#includeiostream.h
#includestdlib.h
intmain()
|
intsize;
cin?size;
int*array=newint[size];
fbr(inti=0;iarrayLi]=rand();
for(i=0;icoutvv'\n'<delete[]array;
return0;
)
九、引用型變量
在C++中,引用是?個(gè)經(jīng)常使用的概念。引用型變量是其他變量的一個(gè)別名,我們可以認(rèn)為
他們只是名字不相同,其他都是相同的。
1.引用是一個(gè)別名
C++中的引用是其他變量的別名。聲明一個(gè)引用型變量,需要給他一個(gè)初始化值,在變量的
生存周期內(nèi),該值不會(huì)改變。&運(yùn)算符定義了一個(gè)引用型變量:
inta;
int&b=a;
先聲明一個(gè)名為a的變量,它還有一個(gè)別名b。我們可以認(rèn)為是一個(gè)人,有一個(gè)真名,一個(gè)
外號(hào),以后不管是喊他a還是b,都是叫他這個(gè)人。同樣,作為變量,以后對(duì)這兩個(gè)標(biāo)識(shí)符
操作都會(huì)產(chǎn)生相同的效果。
#includeiostream.h
intmain()
(
inta=123;
int&b=a;
cout<a++;
cout<b++;
cout<return0;
)
2.引用的初始化
和指針不同,引用變量的值不可改變。引用作為真實(shí)對(duì)象的別名,必須進(jìn)行初始化,除非滿
足下列條件之一:
(1)引用變量被聲明為外部的,它可以在任何地方初始化
(2)引用變量作為類的成員,在構(gòu)造函數(shù)里對(duì)它進(jìn)行初始化
(3)引用變量作為函數(shù)聲明的形參,在函數(shù)調(diào)用時(shí),用調(diào)用者的實(shí)參來進(jìn)行初始化
3.作為函數(shù)形參的引用
引用常常被用作函數(shù)的形參。以引用代替拷貝作為形參的優(yōu)點(diǎn):
引用避免了傳遞大型數(shù)據(jù)結(jié)構(gòu)帶來的額外開銷
引用無須象指針那樣需要使用*和分等運(yùn)算符
#includeiostream,h
voidfuncl(sp);
voidfunc2(s&p);
structs
intn;
chartext[10];
);
intmain()
(
staticsstr={123,China};
fund(str);
func2(str);
return0;
)
voidfuncl(sp)
(
cout<cout<}
voidfunc2(s&p)
(
cout<cout<}
從表面上看,這兩個(gè)函數(shù)沒有明顯區(qū)別,不過他們所花的時(shí)間卻有很大差異,func2()函數(shù)所
用的時(shí)間開銷會(huì)比func2()函數(shù)少很多。它們還有一個(gè)差別,如果程序遞歸funcl(),隨著遞
歸的深入,會(huì)因?yàn)闂5暮谋M而崩潰,但func2()沒有這樣的擔(dān)憂。
4.以引用方式調(diào)用
當(dāng)函數(shù)把引用作為參數(shù)傳遞給另一個(gè)函數(shù)時(shí),被調(diào)用函數(shù)將直接對(duì)參數(shù)在調(diào)用者中的拷貝進(jìn)
行操作,而不是產(chǎn)生一個(gè)局部的拷貝(傳遞變量本身是這樣的)。這就稱為以引用方式調(diào)用。
把參數(shù)的值傳遞到被調(diào)用函數(shù)內(nèi)部的拷貝中則稱為以傳值方式調(diào)用。
#includeiostream.h
voiddisplay(constDate&,constchar*);
voidswapper(Date&,Date&);
structDate
(
intmonth,day,year;
);
intmain()
staticDatenow={2,23,90);
staticDatethen={9,10,60};
display(now,Now:);
display(then,Then:);
swapper(now,then);
display(now,Now:);
display(then,Then:);
return0;
)
voidsw叩per(Date&dll,Date&dt2)
(
Datesave;
save=dt1;
dtl=dt2;
dt2=save;
)
voiddisplay(constDate&dt,constchar*s)
(
cout<cout<}
5.以引用作為返回值
#includeiostream.h
structDate
(
intmonth,day,year;
);
Datebirthdays[]=
(
[12,12,60);
{10,25,85);
{5,20,73};
);
constDate&getdate(intn)
(
returnbirthdays[n-l];
)
intmain()
intdt=l;
while(dt!=O)
cout<cin?dt;
if(dt>0&&dt<4)
(
constDate&bd=getdate(dt);
cout<}
)
return0;
)
程序都很簡(jiǎn)單,就不講解了。類是編程人員表達(dá)自定義數(shù)據(jù)類型的C++機(jī)制。它和C語言
中的結(jié)構(gòu)類似,C++類支持?jǐn)?shù)據(jù)抽象和面向?qū)ο蟮某绦蛟O(shè)計(jì),從某種意義上說,也就是數(shù)據(jù)
類型的設(shè)計(jì)和實(shí)現(xiàn)。
一、類的設(shè)計(jì)
1.類的聲明
class類名
(
private:〃私有
public://公有
2.類的成員
一般在C++類中,所有定義的變量和函數(shù)都是類的成員。如果是變量,我們就叫它數(shù)據(jù)成員
如果是函數(shù),我們就叫它成員函數(shù)。
3.類成員的可見性
private和public訪問控制符決定了成員的可見性。由一個(gè)訪問控制符設(shè)定的可訪問狀態(tài)將?
直持續(xù)到下一個(gè)訪問控制符出現(xiàn),或者類聲明的結(jié)束。私有成員僅能被同一個(gè)類中的成員函
數(shù)訪問,公有成員既可以被同一類中的成員函數(shù)訪問,也可以被其他已經(jīng)實(shí)例化的類中函數(shù)
訪問。當(dāng)然,這也有例外的情況,這是以后要討論的友元函數(shù)。
類中默認(rèn)的數(shù)據(jù)類型是private,結(jié)構(gòu)中的默認(rèn)類型是public。一般情況下,變量都作為私有
成員出現(xiàn),函數(shù)都作為公有成員出現(xiàn)。
類中還有一種訪問控制符protected,叫保護(hù)成員,以后再說明。
4.初始化
在聲明一個(gè)類的對(duì)象時(shí),可以用圓括號(hào)()包含一個(gè)初始化表。
看下面一個(gè)例子:
#includeiostream.h
classBox
private:
intheight,width,depth;//3個(gè)私有數(shù)據(jù)成員
public:
Box(int,int,int);
~Box();
intvolume。;〃成員函數(shù)
);
Box::Box(intht,intwd,intdp)
(
height=ht;
width二wd;
depth=dp;
)
Box::?Box()
(
//nothing
)
intBox::volume()
(
returnheight*width*depth;
)
intmain()
(
Boxthisbox(3,4,5);〃聲明?個(gè)類對(duì)象并初始化
cout<return0;
)
當(dāng)一個(gè)類中沒有private成員和protected成員時(shí),也沒有虛函數(shù),并且不是從其他類中派生
出來的,可以用{}來初始化。(以后再講解)
5.內(nèi)聯(lián)函數(shù)
內(nèi)聯(lián)函數(shù)和普通函數(shù)的區(qū)別是:內(nèi)聯(lián)函數(shù)是在編譯過程中展開的。通常內(nèi)聯(lián)函數(shù)必須簡(jiǎn)短。
定義類的內(nèi)聯(lián)函數(shù)有兩種方法:一種和C語言一樣,在定義函數(shù)時(shí)使用關(guān)鍵字inline。如:
inlineintBox::volume()
(
returnheight*wid山*depth;
還有一種方法就是直接在類聲明的內(nèi)部定義函數(shù)體,而不是僅僅給出一個(gè)函數(shù)原型。我們把
上面的函數(shù)簡(jiǎn)化一下:
#includeiostream.h
classBox
(
private:
intheight,width,depth;
public:
Box(intht,intwd,intdp)
(
height=ht;
width=wd;
depth=dp;
)
~Box();
intvolume()
(
returnheight*width*depth;
)
);
intmain()
(
Boxthisbox(3,4,5);//聲明一個(gè)類對(duì)象并初始化
cout<return0;
)
這樣,兩個(gè)函數(shù)都默認(rèn)為內(nèi)聯(lián)函數(shù)了。
二、構(gòu)造函數(shù)
什么是構(gòu)造函數(shù)?通俗的講,在類中,函數(shù)名和類名相同的函數(shù)稱為構(gòu)造函數(shù)。上面的Box()
函數(shù)就是構(gòu)造函數(shù)。C++允許同名函數(shù),也就允許在一個(gè)類中有多個(gè)構(gòu)造函數(shù)。如果一個(gè)都
沒有,編譯器將為該類產(chǎn)生一個(gè)默認(rèn)的構(gòu)造函數(shù),這個(gè)構(gòu)造函數(shù)可能會(huì)完成些工作,也可
能什么都不做。
絕對(duì)不能指定構(gòu)造函數(shù)的類型,即使是void型都不可以。實(shí)際上構(gòu)造函數(shù)默認(rèn)為void型。
當(dāng)一個(gè)類的對(duì)象進(jìn)入作用域時(shí),系統(tǒng)會(huì)為其數(shù)據(jù)成員分配足夠的內(nèi)存,但是系統(tǒng)不一定將其
初始化。和內(nèi)部數(shù)據(jù)類型對(duì)象一樣,外部對(duì)象的數(shù)據(jù)成員總是初始化為0。局部對(duì)象不會(huì)被
初始化。構(gòu)造函數(shù)就是被用來進(jìn)行初始化工作的。當(dāng)自動(dòng)類型的類對(duì)象離開其作用域時(shí),所
站用的內(nèi)存將釋放回系統(tǒng)。
看上面的例子,構(gòu)造函數(shù)Box()函數(shù)接受三個(gè)整型擦黑素,并把他們賦值給立方體對(duì)象的數(shù)
據(jù)成員。
如果構(gòu)造函數(shù)沒有參數(shù),那么聲明對(duì)象時(shí)也不需要括號(hào)。
1.使用默認(rèn)參數(shù)的構(gòu)造函數(shù)
當(dāng)在聲明類對(duì)象時(shí),如果沒有指定參數(shù),則使用默認(rèn)參數(shù)來初始化對(duì)象。
#includeiostream.h
classBox
(
private:
intheight,width,depth;
public:
Box(intht=2,intwd=3,intdp=4)
(
height=ht;
width=wd;
depth=dp;
)
?Box();
intvolume()
(
returnheight*width*depth;
}
);
intmain()
(
Boxthisbox(3,4,5);〃初始化
Boxdefaulbox;〃使用默認(rèn)參數(shù)
cout<cout<
return0;
)
2.默認(rèn)構(gòu)造函數(shù)
沒有參數(shù)或者參數(shù)都是默認(rèn)值的構(gòu)造函數(shù)稱為默認(rèn)構(gòu)造函數(shù)。如果你不提供構(gòu)造函數(shù),編譯
器會(huì)自動(dòng)產(chǎn)生一個(gè)公共的默認(rèn)構(gòu)造函數(shù),這個(gè)構(gòu)造函數(shù)什么都不做。如果至少提供一個(gè)構(gòu)造
函數(shù),則編譯器就不會(huì)產(chǎn)生默認(rèn)構(gòu)造函數(shù)。
3.重載構(gòu)造函數(shù)
一個(gè)類中可以有多個(gè)構(gòu)造函數(shù)。這些構(gòu)造函數(shù)必須具有不同的參數(shù)表。在一個(gè)類中需要接受
不同初始化值時(shí),就需要編寫多個(gè)構(gòu)造函數(shù),但有時(shí)候只需要一個(gè)不帶初始值的空的Box
對(duì)?象。
#includeiostream.h
classBox
private:
intheight,width,depth;
public:
Box(){//nothing}
Box(intht=2Jntwd=3,intdp=4)
(
height=ht;
width=wd;
depth=dp;
)
~Box();
intvolume()
(
returnheight*width*depth;
)
);
intmain()
(
Boxthisbox(3,4,5);〃初始化
Boxotherbox;
otherbox=thisbox;
cout<return0;
)
這兩個(gè)構(gòu)造函數(shù)一個(gè)沒有初始化值,一個(gè)有。當(dāng)沒有初始化值時(shí),程序使用默認(rèn)值,即2,
3,4o
但是這樣的程序是不好的。它允許使用初始化過的和沒有初始化過的Box對(duì)象,但它沒有
考慮當(dāng)thisbox給otherbox賦值失敗后,volume。該返回什么。較好的方法是,沒有參數(shù)表
的構(gòu)造函數(shù)也把默認(rèn)值賦值給對(duì)象。
classBox
(
intheight,width,depth;
public:
Box()
(
height=O;width=O;depth=O;
)
Box(intht,intwd,intdp)
height=ht;width=wd;depth=dp;
intvolume()
returnheight*width*depth;
)
);
這還不是最好的方法,更好的方法是使用默認(rèn)參數(shù),根本不需要不帶參數(shù)的構(gòu)造函數(shù)。
classBox
(
intheight,width,depth;
public:
Box(intht=O,intwd=0,intdp=O)
(
height=ht;width=wd:depth=dp;
)
intvolume()
(
returnheight*width*depth;
)
);
三、析構(gòu)函數(shù)
當(dāng)一個(gè)類的對(duì)象離開作用域時(shí),析構(gòu)函數(shù)將被調(diào)用(系統(tǒng)自動(dòng)調(diào)用)。析構(gòu)函數(shù)的名字和類名
一樣,不過要在前面加上~。對(duì)一個(gè)類來說,只能允許一個(gè)析構(gòu)函數(shù),析構(gòu)函數(shù)不能有參
數(shù),并且也沒有返回值。析構(gòu)函數(shù)的作用是完成一個(gè)清理工作,如釋放從堆中分配的內(nèi)存。
我們也可以只給出析構(gòu)函數(shù)的形式,而不給出起具體函數(shù)體,其效果是一樣的,如上面的例
子。但在有些情況下,析構(gòu)函數(shù)又是必需的。如在類中從堆中分配了內(nèi)存,則必須在析構(gòu)函
數(shù)中釋放
C++的內(nèi)部數(shù)據(jù)類型遵循隱式類型轉(zhuǎn)換規(guī)則。假設(shè)某個(gè)表達(dá)市中使用了一個(gè)短整型變量,而
編譯器根據(jù)上下文認(rèn)為這兒需要是的長(zhǎng)整型,則編譯器就會(huì)根據(jù)類型轉(zhuǎn)換規(guī)則自動(dòng)把它轉(zhuǎn)換
成長(zhǎng)整型,這種隱式轉(zhuǎn)換出現(xiàn)在賦值、參數(shù)傳遞、返回值、初始化和表達(dá)式中。我們也可以
為類提供相應(yīng)的轉(zhuǎn)換規(guī)則。
對(duì)一個(gè)類建立隱式轉(zhuǎn)換規(guī)則需要構(gòu)造一個(gè)轉(zhuǎn)換函數(shù),該函數(shù)作為類的成員,可以把該類的對(duì)
象和其他數(shù)據(jù)類型的對(duì)象進(jìn)行相互轉(zhuǎn)換。聲明了轉(zhuǎn)換函數(shù),就告訴了編譯器,當(dāng)根據(jù)句法判
定需要類型轉(zhuǎn)換時(shí),就調(diào)用函數(shù)。
有兩種轉(zhuǎn)換函數(shù)。一種是轉(zhuǎn)換構(gòu)造函數(shù);另一種是成員轉(zhuǎn)換函數(shù)。需要采用哪種轉(zhuǎn)換函數(shù)取
決于轉(zhuǎn)換的方向。
一、轉(zhuǎn)換構(gòu)造函數(shù)
當(dāng)一個(gè)構(gòu)造函數(shù)僅有一個(gè)參數(shù),且該參數(shù)是不同于該類的一個(gè)數(shù)據(jù)類型,這樣的構(gòu)造函數(shù)就
叫轉(zhuǎn)換構(gòu)造函數(shù)。轉(zhuǎn)換構(gòu)造函數(shù)把別的數(shù)據(jù)類型的對(duì)象轉(zhuǎn)換為該類的一個(gè)對(duì)象。和其他構(gòu)造
函數(shù)一樣,如果聲明類的對(duì)象的初始化表同轉(zhuǎn)換構(gòu)造函數(shù)的參數(shù)表相匹配,該函數(shù)就會(huì)被調(diào)
用。當(dāng)在需要使用該類的地方使用了別的數(shù)據(jù)類型,便宜器就會(huì)調(diào)用轉(zhuǎn)換構(gòu)造函數(shù)進(jìn)行轉(zhuǎn)換。
#includeiostream.h
#includetime.h
#includestdio.h
classDate
(
intmo,da,yr;
public:
Date(time_t);
voiddisplayO;
);
voidDate::display()
{
charyear[5];
if(yr<10)
sprintf(year,O%d,yr);
else
sprintf(year,%d,yr);
cout<)
Date::Date(time_tnow)
(
tm*tim=localtime(&now);
da=tim->tm_mday;
mo=tim->tm_mon+1;
yr=tim->tm_year;
if(yr>=100)yr-=100;
)
intmain()
(
time_tnow=time(0);
Datedt(now);
dt.displayO;
return0;
}
本程序先調(diào)用time()函數(shù)來獲取當(dāng)前時(shí)間,并把它賦給time」對(duì)象;然后程序通過調(diào)用Date
類的轉(zhuǎn)換構(gòu)造函數(shù)來創(chuàng)建一個(gè)Date對(duì)象,該對(duì)象由time」對(duì)象轉(zhuǎn)換而來。time」對(duì)象先傳
遞給localtime。函數(shù),然后返回一個(gè)指向tm結(jié)構(gòu)(time.h文件中聲明)的指針,然后構(gòu)造函數(shù)
把結(jié)構(gòu)中的日月年的數(shù)值拷貝給Date對(duì)象的數(shù)據(jù)成員,這就完成了從time」對(duì)象到Date對(duì)
象的轉(zhuǎn)換。
二、成員轉(zhuǎn)換函數(shù)
成員轉(zhuǎn)換函數(shù)把該類的對(duì)象轉(zhuǎn)換為其他數(shù)據(jù)類型的對(duì)象。在成員轉(zhuǎn)換函數(shù)的聲明中要用到關(guān)
鍵字operator。這樣聲明一個(gè)成員轉(zhuǎn)換函數(shù):
operatoraaa();
在這個(gè)例子中,aaa就是要轉(zhuǎn)換成的數(shù)據(jù)類型的說明符。這里的類型說明符可以是任何合法
的C++類型,包括其他的類。如下來定義成員轉(zhuǎn)換函數(shù);
Classname:roperatoraaa()
類名標(biāo)識(shí)符是聲明了該函數(shù)的類的類型說明符。上面定義的Date類并不能把該類的對(duì)象轉(zhuǎn)
換回time」型變量,但可以把它轉(zhuǎn)換成一個(gè)長(zhǎng)整型值,計(jì)算從2000年1月1日到現(xiàn)在的天
數(shù)。
#includeiostream.h
classDate
(
intmo,da,yr;
public:
Date(intm,intd,inty){mo=m;da=d;yr=y;}
operatorint();〃聲明
);
Date::operatorint()〃定義
(
staticintdys[]={31,28,31,30,31,30,31,31,30,31,30,31);
intdays=yr-2000;
days*=365;
days+=(yr-2000)/4;
fbr(inti=0;idays+=dys[i];
days+=da;
returndays;
)
intmain()
(
Datenow(12,24,2003);
intsince=now;
cout<return0;
)
三、類的轉(zhuǎn)換
匕面兩個(gè)例子都是C++類對(duì)象和內(nèi)部數(shù)據(jù)對(duì)象之間的相互轉(zhuǎn)換。也可以定義轉(zhuǎn)換函數(shù)來實(shí)現(xiàn)
兩個(gè)類對(duì)象之間的相互轉(zhuǎn)換。
#includeiostream.h
classCustomDate
(
public:
intda,yr;
CustomDate(intd=O,inty=0){da=d;yr=y;}
voiddisplayO
(
cout<}
);
classDate
(
intmo,da,yr;
public:
Date(intm=0,intd=O,inty=0){mo=m;da=d;yr=y;}
Date(constCustomDate&);〃轉(zhuǎn)換構(gòu)造函數(shù)
operatorCustomDate。;〃成員轉(zhuǎn)換函數(shù)
voiddisplayO
(
cout<)
);
staticintdys[]={31,28,31,30,31,30,31,31,30,31,30,31);
Date::Date(constCustomDate&jd)
(
yr=jd.yr;
da=jd.da;
fbr(mo=0;mo<ll;mo++)
if(da>dys[mo])da-=dys[mo];
elsebreak;
mo++;
)
Date::operatorCustomDate()
(
CustomDatecd(0,yr);
for(inti=0;icd.da+=da;
returncd;
intmain()
Datedt(12,24,3);
CustomDatecd;
cd=dt;〃調(diào)用成員轉(zhuǎn)換函數(shù)
cd.display();
dt=cd;〃調(diào)用轉(zhuǎn)換構(gòu)造函數(shù)
dt.display();
return0;
)
這個(gè)例子中有兩個(gè)類customDate和Date,CustomDate型日期包含年份和天數(shù)。
這個(gè)例子沒有考慮閏年情況。但是在實(shí)際構(gòu)造一個(gè)類時(shí),應(yīng)該考慮到所有問題的可能性。
在Date里中具有兩種轉(zhuǎn)換函數(shù),這樣,當(dāng)需要從Date型變?yōu)镃ustomDate型十,可以調(diào)用
成員轉(zhuǎn)換函數(shù);反之可.以調(diào)用轉(zhuǎn)換構(gòu)造函數(shù)。
不能既在Date類中定義成員轉(zhuǎn)換函數(shù),又在CustomDate類里定義轉(zhuǎn)換構(gòu)造函數(shù)。那樣編譯
器在進(jìn)行轉(zhuǎn)換時(shí)就不知道該調(diào)用哪一個(gè)函數(shù),從而出錯(cuò)。
四、轉(zhuǎn)換函數(shù)的調(diào)用
C++里調(diào)用轉(zhuǎn)換函數(shù)有三種形式:第一種是隱式轉(zhuǎn)換,例如編譯器需要一個(gè)Date對(duì)象,而
程序提供的是CustomDate對(duì)象,編譯器會(huì)自動(dòng)調(diào)用合適的轉(zhuǎn)換函數(shù)。另外兩種都是需要在
程序代碼中明確給出的顯式轉(zhuǎn)換。C++強(qiáng)制類型轉(zhuǎn)換是一種,還有一種是顯式調(diào)用轉(zhuǎn)換構(gòu)造
函數(shù)和成員轉(zhuǎn)換函數(shù)。下面的程序給出了三中轉(zhuǎn)換形式:
#includeiostream.h
classCustomDate
(
public:
intda,yr;
CustomDate(intd=O,inty=0){da=d;yr=y;}
voiddisplayO
(
cout<)
);
classDate
(
intmo,da,yr;
public:
Date(intm,intd,inty)
(
mo=m;da=d;yr=y;
operatorCustomDate();
);
Date::operatorCustomDate()
(
staticintdys[]={31,28,31,30,31,30,31,31,30,31,30,31);
CustomDatecd(0,yr);
for(inti=0;icd.da+=da;
returncd;
)
intmain()
(
Datedt(l1,17,89);
CustomDatecd;
cd=dt;
cd.displayO;
cd=(CustomDate)dt;
cd.displayO;
cd=CustomDate(dt);
cd.displayO;
return0;
)
五、轉(zhuǎn)換發(fā)生的情形
匕面的幾個(gè)例子都是通過不能類型對(duì)象之間的相互賦值來調(diào)用轉(zhuǎn)換函數(shù),還有兒種調(diào)用的可
能:
參數(shù)傳遞
初始化
返回值
表達(dá)式語句
這些情況下,都有可能調(diào)用轉(zhuǎn)換函數(shù)。
下面的程序不難理解,就不分析了。
#includeiostream.h
classCustomDate
(
public:
intda,yr;
CustomDate(){}
CustomDate(intd,inty){da=d;yr=y;}
voiddisplayO
(
cout<)
);
classDate
(
intmo,da,yr;
public:
Date(intmjntdjnty){mo=m;da=d;yr=y;}
operatorCustomDate();
);
Date::operatorCustomDate()
(
staticintdys[]={31,28,31,30,31,30,31,31,30,31,30,31);
CustomDatecd(0,yr);
for(inti=0;icd.da+=da;
returncd;
}
classTester
(
CustomDatecd;
public:
explicitTester(CustomDatec){cd=c;}
voiddisplayO{cd.displayO;)
);
voiddispdate(CustomDatecd)
(
cd.displayO;
)
CustomDatertndate()
(
Date出(9,11,1);
returndt;
)
intmain()
Datedt(12,24,3);
CustomDatecd;
cd=dt;
cd.displayO;
dispdate(dt);
Testerts(dt);
ts.displayO;
cd=rtndate();
cd.display();
return0;
)
六、顯式構(gòu)造函數(shù)
注意上面Tester類的構(gòu)造函數(shù)前面有一個(gè)explicit修飾符。如果不加上這個(gè)關(guān)鍵字,那么在
需要把CustomDate對(duì)象轉(zhuǎn)換成Tester對(duì)象時(shí);編譯器會(huì)把該函數(shù)當(dāng)作轉(zhuǎn)換構(gòu)造函數(shù)來調(diào)用。
但是有時(shí)候,并不想把這種只有一個(gè)參數(shù)的構(gòu)造函數(shù)用于轉(zhuǎn)換目的,而僅僅希望用它來顯式
地初始化對(duì)象,此時(shí),就需要在構(gòu)造函數(shù)前加explicit。如果在聲明了Tester對(duì)象以后使用
了下面的語句將導(dǎo)致一個(gè)錯(cuò)誤:
ts=jd;//error
這個(gè)錯(cuò)誤說明,雖然Tester類中有?個(gè)以Date型變量為參數(shù)的構(gòu)造函數(shù),編譯器卻不會(huì)把
它看作是從Date到Tester的轉(zhuǎn)換構(gòu)造函數(shù),因?yàn)樗穆暶髦邪薳xplicit修飾符。
七、表達(dá)式內(nèi)部的轉(zhuǎn)換
在表達(dá)式內(nèi)部,如果發(fā)現(xiàn)某個(gè)類型和需要的不一致,就會(huì)發(fā)生錯(cuò)誤。數(shù)字類型的轉(zhuǎn)換是很簡(jiǎn)
單,這里就不舉例了。下面的程序是把Date對(duì)象轉(zhuǎn)換成長(zhǎng)整型值。
#includeiostream.h
classDate
(
intmo,da,yr;
public:
Date(intm,intd,inty)
(
mo=m;da=d;yr=y;
)
operatorlong();
Date:operatorlong()
staticintdys[]={31,28,31,30,31,30,31,31,30,31,30,31);
longdays=yr;
days*=365;
days+=(yr-1900)/4;M1900年1月1日開始計(jì)算
for(inti=0;idays+=da;
returndays;
)
intmain()
(
Datetoday(12,24,2003);
constlongott=123;
longsum=ott+today;
cout<return0;
)
在表達(dá)式中,當(dāng)需要轉(zhuǎn)換的對(duì)象可以轉(zhuǎn)換成某個(gè)數(shù)字類型,或者表達(dá)式調(diào)用了作用于某個(gè)類
的重載運(yùn)算符時(shí),就會(huì)發(fā)生隱式轉(zhuǎn)換。運(yùn)算符重載以后再學(xué)習(xí)。一、私有數(shù)據(jù)成員的使川
1.取值和賦值成員函數(shù)
面向?qū)ο蟮募s定就是保證所有數(shù)據(jù)成員的私有性。一般我們都是通過公有成員函數(shù)來作為公
共接口來讀取私有數(shù)據(jù)成員的。某些時(shí)候,我們稱這樣的函數(shù)為取值和賦值函數(shù)。
取值函數(shù)的返回值和傳遞給賦值函數(shù)的參數(shù)不必一一匹配所有數(shù)據(jù)成員的類型。
#includeiostream.h
classDate
(
intmo,da,yr;
public:
Date(intm,intd,inty){mo=m;da=d;yr=y;}
intgetyear()const{returnyr;)
voidsetyear(inty){yr=y;}
);
intmain()
(
Datedt(4,l,89);
cout<dt.setyear(97);
cout<return0;
)
上面的例子很簡(jiǎn)單,不分析了。要養(yǎng)成這樣的習(xí)慣,通過成員函數(shù)來訪問和改變類中的數(shù)據(jù)。
這樣有利于軟件的設(shè)計(jì)和維護(hù)。比如,改變Date類內(nèi)部數(shù)據(jù)的形式,但仍然用修改過的
getyear()filsetyear。來提供訪問接口,那么使用該類就不必修改他們的代碼,僅需要重新編
譯程序即可。
2.常量成員函數(shù)
注意上面的程序中g(shù)etyear()被聲明為常量型,這樣可以保證該成員函數(shù)不會(huì)修改調(diào)用他的對(duì)
象。通過加上.const修飾符,可以使訪問對(duì)象數(shù)據(jù)的成員函數(shù)僅僅完成不會(huì)引起數(shù)據(jù)變動(dòng)的
那些操作。
如果程序聲明某個(gè)Date對(duì)象為常量的話,那么該對(duì)象不得調(diào)用任何非常量型成員函數(shù),不
論這些函數(shù)是否真的試圖修改對(duì)象的數(shù)據(jù)。只有把那些不會(huì)引起數(shù)據(jù)改變的函數(shù)都聲明為常
量型,才可以讓常量對(duì)象來調(diào)用。
3.改進(jìn)的成員轉(zhuǎn)換函數(shù)
下面的程序改進(jìn)了從Date對(duì)象到CustomDate對(duì)象的成員轉(zhuǎn)換函數(shù),用取值和賦值函數(shù)取代
了使用公有數(shù)據(jù)成員的做法。(以前的程序代碼在上一帖中)
#includeiostream.h
classCustomDate
(
intda,yr;
public:
CustomDate(){}
CustomDate(intd,inty){da=d;yr=y;}
voiddisplayOconst{cout<intgetdayOconst{returnda;}
voidsetday(intd){da=d;}
);
classDate
(
intmo,da,yr;
public:
Date(intmjntd,inty){mo=m;da=d;yr=y;}
operatorCustomDate()const;
);
Date::operatorCustomDate()const
(
staticintdys[]={31,28,31,30,31,30,31,31,30,31,30,31};
CustomDatecd(0,yr);
intday=da;
fbr(inti=0;icd.setday(day);
returncd;
)
intmain()
Datedt(l1,17,89);
CustomDatecd;
cd=dt;
cd.displayO;
return0;
)
注意上面的程序中Date::operatorCustomDate。聲明為常量型,因?yàn)檫@個(gè)函數(shù)沒有改變調(diào)用它
對(duì)象的數(shù)據(jù),盡管它修改了一個(gè)臨時(shí)CustomDate對(duì)象并將其作為函數(shù)返回值。
二、友元
前面已經(jīng)說過了,私有數(shù)據(jù)成員不能被類外的其他函數(shù)讀取,但是有時(shí)候類會(huì)允許一些特殊
的函數(shù)直接讀寫其私有數(shù)據(jù)成員。
關(guān)鍵字friend可以讓特定的函數(shù)或者別的類的所有成員函數(shù)對(duì)私有數(shù)據(jù)成員進(jìn)行讀寫。這既
可以維護(hù)數(shù)據(jù)的私有性,有可以保證讓特定的類或函數(shù)能夠直接訪問私有數(shù)據(jù)。
1.友元類
一個(gè)類可以聲明另一個(gè)類為其友元,這個(gè)友元的所有成員函數(shù)都可以讀寫它的私有數(shù)據(jù)。
#includeiostream.h
classDate;
classCustomDate
(
intda,yr;
public:
CustomDate(intd=O,inty=0){da=d;yr=y;}
voiddisplayOconst{cout<friendDate;〃這兒
);
classDate
(
intmo,da,yr;
public:
Date(intm,intd,inty){mo=m;da=d;yr=y;}
operatorCustomDate();
);
Date::operatorCustomDate()
(
staticintdys[]={31,28,31,30,31,30,31,31,30,31,30,31};
CustomDatecd(0,yr);
for(inti=0;icd.da+=da;
returncd;
intmain()
(
Datedt(l1,17,89);
CustomDatecd(dt);
cd.display();
return0;
)
在上面的程序中,有這樣一句friendDate;該語句告訴編譯器,Date類的所有成員函數(shù)有權(quán)
訪問CustomDate類的私有成員。因?yàn)镈ate類的轉(zhuǎn)換函數(shù)需要知道CustomDate類的每個(gè)數(shù)
據(jù)成員,所以真?zhèn)€Date類都被聲明為CustomDate類的友元。
2.隱式構(gòu)造函數(shù)
上面程序?qū)ustomDate的構(gòu)造函數(shù)的調(diào)用私有顯示該類需要如下的一個(gè)轉(zhuǎn)換構(gòu)造函數(shù):
CustomDate(Date&dt);
但是唯一的一個(gè)構(gòu)造函數(shù)是:CustomDate(intd=O;inty=0);
這就出現(xiàn)了問題,編譯器要從Date對(duì)象構(gòu)造,■個(gè)CustomDate對(duì)象,但是CustomDate類中
并沒有定義這樣的轉(zhuǎn)換構(gòu)造函數(shù)。不過Date類中定義了一個(gè)成員轉(zhuǎn)換函數(shù),它可以把Date
對(duì)象轉(zhuǎn)換成CustomDate對(duì)象。于是編譯器開始搜索CustomDate類,看其是否有一個(gè)構(gòu)造函
數(shù),能從一個(gè)已存在的CustomDate的對(duì)象創(chuàng)建新的CustomDate對(duì)象。這種構(gòu)造函數(shù)叫拷貝
構(gòu)造函數(shù)。拷貝構(gòu)造函數(shù)也只有一個(gè)參數(shù),該參數(shù)是它所屬的類的一個(gè)對(duì)象,由于
CustomDate類中沒有拷貝構(gòu)造函數(shù),于是編譯器就會(huì)產(chǎn)生一個(gè)默認(rèn)的拷貝構(gòu)造函數(shù),該函
數(shù)簡(jiǎn)單地把已存在的對(duì)象的每個(gè)成員拷貝給新對(duì)象?,F(xiàn)在我們已經(jīng)知道,編譯器可以把Date
對(duì)象轉(zhuǎn)換成CustomDate對(duì)象,也可以從已存在的CustomDate對(duì)象生成—1K新的CustomDate
對(duì)象。那么上面提出的問題,編譯器就是這樣做的:它首先調(diào)用轉(zhuǎn)換函數(shù),從Date對(duì)象創(chuàng)
建一個(gè)隱臧的、臨時(shí)的、匿名的CustomDate對(duì)象,然后用該臨時(shí)對(duì)象作為參數(shù)調(diào)用默認(rèn)拷
貝構(gòu)造函數(shù),這就生成了一個(gè)新的CustomDate對(duì)象。
3.預(yù)引用
上面的例子中還有這樣,?句classDate;
這個(gè)語句叫做預(yù)引用。它告訴編譯器,類Date將在后面定義。編譯器必須知道這個(gè)信號(hào),
因?yàn)镃ustomDate類中引用了Date類,而Date里也引用了CustomDate類,必須首先聲明其
中之一。
使用了預(yù)引用后,就可以聲明未定義的類的友元、指針和引用。但是不可以使用那些需要知
道預(yù)引用的類的定義細(xì)節(jié)的語句,如聲明該類的?個(gè)實(shí)例或者任何對(duì)該類成員的引用。
4.顯式友元預(yù)引用
也可以不使用預(yù)引用,這只要在聲明友元的時(shí)候加上關(guān)鍵自class就行了。
#includeiostream.h
classCustomDate
{
intda,yr;
public:
CustomDate(intd=O,inty=0){da=d;yr=y;}
voiddisplayOconst{cout<friendclassDate;〃這兒,去掉前面的預(yù)引用
);
classDate
Date::operatorCustomDate()
intmain()
5.友元函數(shù)
通常,除非真的需要,否則并不需要把整個(gè)類都設(shè)為另一個(gè)類的友元,只需挑出需要訪問當(dāng)
前類私有數(shù)據(jù)成員的成員函數(shù),將它們?cè)O(shè)置為該類的友元即可。這樣的函數(shù)稱為友元函數(shù)。
下面的程序限制了CustomDate類數(shù)據(jù)成員的訪問,Date類中只有需要這些數(shù)據(jù)的成員函數(shù)
才有權(quán)讀寫它們。
#includeiostream.h
classCustomDate;
classDate
(
intmo,da,yr;
public:
Date(constCustomDate&);
voiddisplayOconst{cout<};
classCustomDate
(
intda,yr;
public:
CustomDate(intd=O,inty=0){da=d;yr=y;}
friendDate::Date(constCustomDate&);
Date::Date(constCustomDate&cd)
(
staticintdys[]={31,28,31,30,31,30,31,31,30,31,30,31);
yr=cd.yr;
da=cd.da;
fbr(mo=0;mo<l1;mo++)
if(da>dys[mo|)da-=dys[mo];
elsebreak;
mo++;
)
intmain()
(
Datedt(CustomDate(123,89));
dt.displayO;
return0;
)
6.匿名對(duì)象
上面main。函數(shù)中Date對(duì)象調(diào)用CustomDate類的構(gòu)造函數(shù)創(chuàng)建了一個(gè)匿名CustomDate對(duì)
象,然后用該對(duì)象創(chuàng)建了一個(gè)Date對(duì)象。這種用法在C++中是經(jīng)常出現(xiàn)的。
7.非類成員的友元函數(shù)
有時(shí)候友元函數(shù)未必是某個(gè)類的成員。這樣的函數(shù)擁有類對(duì)象私有數(shù)據(jù)成員的讀寫權(quán),但它
并不是任何類的成員函數(shù)。這個(gè)特性在重載運(yùn)算符時(shí)特別有用。
非類成員的友元函數(shù)通常被用來做為類之間的紐帶。一個(gè)函數(shù)如果被兩個(gè)類同時(shí)聲明為友
元,它就可以訪問這兩個(gè)類的私有成員。下面的程序說明了一個(gè)可以訪問兩個(gè)類私有數(shù)據(jù)成
員的友元函數(shù)是如何將在兩個(gè)類之間架起橋梁的。
#includeiostream.h
classTime;
classDate
(
intmo,da,yr;
public:
Date(intm,intd,inty){mo=m;da=d;yr=y;}
friendvoiddisplay(constDate&,constTime&);
);
classTime
(
inthr,min,sec;
public:
Time(inth,intm,ints){hr=h;min=m;sec=s;}
friendvoiddisplay(constDate&,constTime&);
);
voiddisplay(constDate&dt,constTime&tm)
(
cout?dt.mo?7'?dt.da?7,?dt.yr;
cout?*
cout?tm.hr??tm.min??tm.sec;
)
intmain()
(
Datedt(2,16,97);
Timetm(10,55,0);
display(dt,tm);
return0;
}一、析構(gòu)函數(shù)
前面的一些例子都沒有說明析構(gòu)函數(shù),這是因?yàn)樗玫降念愒诮Y(jié)束時(shí)不需要做特別的清理工
作。下面的程序給出了一新的Date類,其中包括一個(gè)字符串指針,用來表示月份。
#includeiostream.h
#includestring.h
classDate
(
intmo,da,yr;
char*month;
public:
Date(intm=0,intd=0,inty=0);
?Date。;
voiddisplayOconst;
);
Date::Date(intmjntdjnty)
(
staticchar*mos[]=
(
January,February,March,April,May,June,
July,August,September,October,November,December
);
mo=m;da=d;yr=y;
if(m!=0)
month=newchar[strlen(mos[m-l])+l|;
strcpy(month,mos[m-l]);
)
elsemonth=0;
Date::?Date。
(
delete[]month;
)
voidDate::display()const
(
if(month!=0)cout<)
intmain()
(
Datebirthday(8,l1,1979);
birthday.display();
return0;
}
在Date對(duì)象的構(gòu)造函數(shù)中,首先用new運(yùn)算符為字符串month動(dòng)態(tài)分配了內(nèi)存,然后從內(nèi)
部數(shù)組中把月份的名字拷貝給字符串指針month。
析構(gòu)函數(shù)在刪除month指針時(shí):可能會(huì)出現(xiàn)一些問題。當(dāng)然從這個(gè)程序本身來看,沒什么
麻煩;但是從設(shè)計(jì)一個(gè)類的角度來看,當(dāng)Date類用于賦值時(shí),就會(huì)出現(xiàn)問題。假設(shè)上面的
main。修改為“
intmain()
(
Datebirthday(8,ll,1979);
Datetoday;
today=birthday;
birthday.displayO;
return0;
)
這會(huì)生成一個(gè)名為today的空的Date型變量,并且把birthday值賦給它。如果不特別通知編
譯器,它會(huì)簡(jiǎn)單的認(rèn)為類的賦值就是成員對(duì)成員的拷貝。在上面的程序中,變量birthday有
一個(gè)字符型指針month,并且在構(gòu)造函數(shù)里用new運(yùn)算符初始化過了。當(dāng)birthday離開其作
用域時(shí),析構(gòu)函數(shù)會(huì)調(diào)用delete運(yùn)算符來釋放內(nèi)存。但同時(shí),當(dāng)today離開它的作用域時(shí),
析構(gòu)函數(shù)同樣會(huì)對(duì)它進(jìn)行釋放操作,而today里的month指針是birthday里的momh指針的
一個(gè)拷貝。析構(gòu)函數(shù)對(duì)同一指針進(jìn)行了兩次刪除操作,這會(huì)帶來不可預(yù)知的后果。
如果假設(shè)today是一個(gè)外部變量,而birthday是一個(gè)自變量。當(dāng)birthday離開其作用域時(shí),
就已經(jīng)把對(duì)象today里的month指針刪除了。顯然這也是不正確的。
再假設(shè)有兩個(gè)初始化的Date變量,把其中一個(gè)的值賦值給另一個(gè):
Datebirthday(8Jl,1979);
Datetoday(12,29,2003);
today=birthday;
問題就更復(fù)雜了,當(dāng)這兩個(gè)變量離開作用域時(shí):birthday中的month的值已經(jīng)通過賦值傳遞
給了todayo而today中構(gòu)造函數(shù)用new運(yùn)算符給month的值卻因?yàn)橘x值被覆蓋了。這樣,
birthday中的month被刪除了兩次,而today中month卻沒有被刪除掉。
二、重載賦值運(yùn)算符
為了解決上面的問題,我們應(yīng)該寫一個(gè)特殊的賦值運(yùn)算符函數(shù)來處理這類問題。當(dāng)需要為同
一個(gè)類的兩個(gè)對(duì)象相互賦值時(shí),就可以用載運(yùn)算符函數(shù)。這個(gè)方法可以解決類的賦值和指針
的釋放。
下面的程序中,類中的賦值函數(shù)用new運(yùn)算符從堆中分配了一個(gè)不同的指針,該指針獲取
賦值對(duì)象中相應(yīng)的值,然后拷貝給接受賦值的對(duì)象。
在類中重載賦值運(yùn)算符的格式如下:
voidoperator=(constDate&)
后面我們回加以改進(jìn)。目前,重載的運(yùn)算符函數(shù)的返回類型為void。它是類總的成員函數(shù),
在本程序紅,是Date類的成員函數(shù)。它的函數(shù)名始終是operator二,參數(shù)也始終是同一個(gè)類
的對(duì)象的引用。參數(shù)表示的是源對(duì)象,即賦值數(shù)據(jù)的提供者。重載函數(shù)的運(yùn)算符作為目標(biāo)對(duì)
象的成員函數(shù)來使用。
#includeiostream.h
#includestring.h
classDate
(
intmo,da,yr;
char*month;
public:
Date(intm=0,intd=0,inty=0);
-Date();
voidoperator=(constDate&);
voiddisplayOconst;
);
Date::Date(intm,intd,inty)
(
staticchar*mos[]=
(
January,February,March,April,May,June,
July,August,September,October,November,December
);
mo=m;da=d;yr=y;
if(m!=0)
(
month=newchar[strlen(mos[m-1])+1];
strcpy(month,mos[m-l]);
)
elsemonth=0;
Date::-Date()
(
delete[]month;
voidDate::display()const
(
if(month!=0)cout<charname[25];
cin?name;
if(strncmp(name,end,3)==0)break;
ListEntry*list=newListEntry(name);
if(prev!=0)prev->AddEntry(*list);
prev=list;
)
while(prev!=0)
(
prev->display();
ListEntry*hold=prev;
prev=prev->PrevEntry();
deletehold;
)
return0;
程序運(yùn)行時(shí),會(huì)提示輸入一串姓名,當(dāng)輸入完畢后,鍵入end,然后程序會(huì)逆序顯示剛才輸
入的所有姓名。
程序中ListEntry類含有一個(gè)字符串和一個(gè)指向前一個(gè)表項(xiàng)的指針。構(gòu)造函數(shù)從對(duì)中獲取內(nèi)
存分配給字符串,并把字符串的內(nèi)容拷貝到內(nèi)存,然后置鏈接指針為NULL。析構(gòu)函數(shù)將釋
放字符串所占用的內(nèi)存。
成員函數(shù)PrevEntryO返回指向鏈表前一個(gè)表項(xiàng)的指針。另個(gè)成員函數(shù)顯示當(dāng)前的表項(xiàng)內(nèi)
容。
成員函數(shù)AddEntryO,它把this指針拷貝給參數(shù)的preventry指針,即把當(dāng)前表項(xiàng)的地址賦
值給下一個(gè)表項(xiàng)的鏈接指針,從而構(gòu)造了?個(gè)鏈表。它并沒有改變調(diào)用它的listEntry對(duì)象的
內(nèi)容,只是把該對(duì)象的地址賦給函數(shù)的參數(shù)所引用的那個(gè)ListEntry對(duì)象的preventry指針,
盡管該函數(shù)不會(huì)修改對(duì)象的數(shù)據(jù),但它并不是常量型。這是因?yàn)?,它拷貝?duì)象的地址this
指針的內(nèi)容給一個(gè)非長(zhǎng)常量對(duì)象,而編譯器回認(rèn)為這個(gè)非常量對(duì)象就有可能通過拷貝得到的
地址去修改當(dāng)前對(duì)象的數(shù)據(jù),因此AddEntryO函數(shù)在聲明時(shí)不需要用const。一、類對(duì)象數(shù)
組
類的對(duì)象和C++其他數(shù)據(jù)類型一樣,也可以為其建立數(shù)組,數(shù)組的表示方法和結(jié)構(gòu)一樣。
#includeiostream.h
classDate
(
intmo,da,yr;
public:
Date(intm=0,intd=0,inty=0){mo=m;da=d;yr=y;}
voiddisplayOconst{cout<};
intmain()
(
Datedates[2];
Datetoday(12,31,2003);
dates[O]=today;
dates[0].displayO;
dates[l].displayO;
return0;
1.類對(duì)象數(shù)組和默認(rèn)構(gòu)造函數(shù)
在前面已經(jīng)說過,不帶參數(shù)或者所有參數(shù)都有默認(rèn)值的構(gòu)造函數(shù)叫做默認(rèn)構(gòu)造函數(shù)。如果類
中沒有構(gòu)造函數(shù),編譯器會(huì)自動(dòng)提供一個(gè)什么都不做的公共默認(rèn)構(gòu)造函數(shù)。如果類當(dāng)中至
少有個(gè)構(gòu)造函數(shù),編譯器就不會(huì)提供默認(rèn)構(gòu)造函數(shù)。
如果類當(dāng)中不含默認(rèn)構(gòu)造函數(shù),則無法實(shí)例化其對(duì)象數(shù)組。因?yàn)閷?shí)例花類對(duì)象數(shù)組的格式不
允許用初始化值來匹配某個(gè)構(gòu)造函數(shù)的參數(shù)表。
上面的程序中,main()函數(shù)聲明了一個(gè)長(zhǎng)度為2的Date對(duì)象數(shù)組,還有一個(gè)包含初始化值
的單個(gè)Date對(duì)象。接著把這個(gè)初始化的Date對(duì)象賦值給數(shù)組中第一個(gè)對(duì)象,然后顯示兩個(gè)
數(shù)組元素中包含的日期。從輸出中可以看到,第一個(gè)日期是有效日期,而第二個(gè)顯示的都是
0。
當(dāng)聲明了某個(gè)類的對(duì)象數(shù)組時(shí),編譯器會(huì)為每個(gè)元素都調(diào)用默認(rèn)構(gòu)造函數(shù)。
下面的程序去掉了構(gòu)造函數(shù)的默認(rèn)參數(shù)值,并且增加了一個(gè)默認(rèn)構(gòu)造函數(shù)。
#include
classDate
intmo,da,yr;
public:
Date();
Date(intm,intd,inty){mo=m;da=d;yr=y;}
voiddisplayOconst{cout<};
Date::Date()
(
cout<mo=0;da=0;yr=0;
)
intmain()
(
Datedates[2];
Datetoday。2,31,2003);
dates[0]=today;
dates[0].displayO;
dates[l].displayO;
return0;
)
運(yùn)行程序,輸出為:
Dateconstmctorrunning
Dateconstructorrunning
12/31/2003
0/0/0
從輸出中可以看出,Date。這個(gè)默認(rèn)構(gòu)造函數(shù)被調(diào)用了兩次。
2.類對(duì)象數(shù)組和析構(gòu)函數(shù)
當(dāng)類對(duì)象離開作用域時(shí),編譯器會(huì)為每個(gè)對(duì)象數(shù)組元素調(diào)用析構(gòu)函數(shù)。
#includeiostream.h
classDate
{
intmo,da,yr;
public:
Date(intm=0,intd=0,inty=0){mo=m;da=d;yr=y;}
~Date(){cout<voiddisplayOconst{cout<};
intmain()
(
Datedates[2];
Datetoday(12,31,2003);
dates[O]=today;
dates[O|.display();
dates[l].display();
return0;
)
運(yùn)行程序,輸出為:
12/31/2003
0/0/0
Datedestructorrunning
Datedestructorrunning
Datedestruc
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝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ù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度專業(yè)園藝設(shè)計(jì)施工合同3篇
- 2024年金融科技服務(wù)平臺(tái)委托合同
- 2025年度餐飲企業(yè)食品安全管理體系建設(shè)合同范本3篇
- 二零二五年度租賃鏟車附帶工程驗(yàn)收合同3篇
- 二零二五版企業(yè)社會(huì)責(zé)任LOGO設(shè)計(jì)合同3篇
- 2024年高標(biāo)準(zhǔn)管溝開挖工程合同
- 2025年度離婚協(xié)議及子女監(jiān)護(hù)權(quán)及財(cái)產(chǎn)分割合同3篇
- 2024裝飾項(xiàng)目工程承包合同版B版
- 2025年度航空航天器零部件加工與供應(yīng)合同規(guī)范4篇
- 年度其它網(wǎng)絡(luò)系統(tǒng)專用設(shè)備戰(zhàn)略市場(chǎng)規(guī)劃報(bào)告
- 2025年工程合作協(xié)議書
- 2025年山東省東營(yíng)市東營(yíng)區(qū)融媒體中心招聘全媒體采編播專業(yè)技術(shù)人員10人歷年高頻重點(diǎn)提升(共500題)附帶答案詳解
- 2025年宜賓人才限公司招聘高頻重點(diǎn)提升(共500題)附帶答案詳解
- KAT1-2023井下探放水技術(shù)規(guī)范
- 垃圾處理廠工程施工組織設(shè)計(jì)
- 天皰瘡患者護(hù)理
- 駕駛證學(xué)法減分(學(xué)法免分)題庫(kù)及答案200題完整版
- 2024年四川省瀘州市中考英語試題含解析
- 2025屆河南省九師聯(lián)盟商開大聯(lián)考高一數(shù)學(xué)第一學(xué)期期末學(xué)業(yè)質(zhì)量監(jiān)測(cè)模擬試題含解析
- 撫養(yǎng)權(quán)起訴狀(31篇)
- 2024年“一崗雙責(zé)”制度(五篇)
評(píng)論
0/150
提交評(píng)論