C++ 構(gòu)造函數(shù)與析構(gòu)函數(shù)

構(gòu)造函數(shù)與析構(gòu)函數(shù)

OOP第二課

1、構(gòu)造函數(shù)

1.1 構(gòu)造函數(shù)具有一些特殊的性質(zhì)

1.2 定義構(gòu)造函數(shù)的一般形式

1.3 利用構(gòu)造函數(shù)創(chuàng)建對(duì)象

2、成員初始化表

3、缺省參數(shù)的構(gòu)造函數(shù)

4、重載構(gòu)造函數(shù)

5、拷貝構(gòu)造函數(shù)

5.1 自定義拷貝構(gòu)造函數(shù)

5.2 缺省的拷貝構(gòu)造函數(shù)

5.3 調(diào)用拷貝構(gòu)造函數(shù)的三種情況

5.4 淺拷貝和深拷貝

6、析構(gòu)函數(shù)

7、調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)的順序

8、對(duì)象的生存期

創(chuàng)一個(gè)小群,供大家學(xué)習(xí)交流聊天

如果有對(duì)學(xué)C++方面有什么疑惑問題的,或者有什么想說的想聊的大家可以一起交流學(xué)習(xí)一起進(jìn)步呀。

也希望大家對(duì)學(xué)C++能夠持之以恒

C++愛好群,

如果你想要學(xué)好C++最好加入一個(gè)組織,這樣大家學(xué)習(xí)的話就比較方便,還能夠共同交流和分享資料,給你推薦一個(gè)學(xué)習(xí)的組織:快樂學(xué)習(xí)C++組織 可以點(diǎn)擊組織二字,可以直達(dá)


構(gòu)造函數(shù)和析構(gòu)函數(shù)都是類的成員函數(shù),但它們都是特殊的成員函數(shù),執(zhí)行特殊的功能,不用調(diào)用便自動(dòng)執(zhí)行,而且這些函數(shù)的名字與類的名字有關(guān)。

C++語言中有一些成員函數(shù)性質(zhì)是特殊的,這些成員函數(shù)負(fù)責(zé)對(duì)象的建立、刪除。這些函數(shù)的特殊性在于可以由編譯器自動(dòng)地隱含調(diào)用,其中一些函數(shù)調(diào)用格式采用運(yùn)算符函數(shù)重載的語法。

C++引進(jìn)一個(gè)自動(dòng)完成對(duì)象初始化過程的機(jī)制,這就是類的構(gòu)造函數(shù)。

對(duì)象的初始化

1、數(shù)據(jù)成員是不能在聲明類時(shí)初始化

2、類型對(duì)象的初始化方法:

1) 調(diào)用對(duì)外接口(public成員函數(shù))實(shí)現(xiàn):聲明類→定義對(duì)象→調(diào)用接口給成員賦值

2) 應(yīng)用構(gòu)造函數(shù)(constructor) 實(shí)現(xiàn):聲明類→定義對(duì)象→同時(shí)給成員賦值

1、構(gòu)造函數(shù)

構(gòu)造函數(shù)是一種特殊的成員函數(shù),它主要用于為對(duì)象分配空間,進(jìn)行初始化。

1.1 構(gòu)造函數(shù)具有一些特殊的性質(zhì):

(1) 構(gòu)造函數(shù)的名字必須與類名相同。

(2) 構(gòu)造函數(shù)可以有任意類型的參數(shù),但不能指定返回類型。 它有隱含的返回值,該值由系統(tǒng)內(nèi)部使用。

(3) 構(gòu)造函數(shù)是特殊的成員函數(shù),函數(shù)體可寫在類體內(nèi),也可寫在類體外。

(4) 構(gòu)造函數(shù)可以重載,即一個(gè)類中可以定義多個(gè)參數(shù)個(gè)數(shù)或參數(shù)類型不同的構(gòu)造函數(shù)。構(gòu)造函數(shù)是不能繼承

(5) 構(gòu)造函數(shù)被聲明為公有函數(shù),但它不能像其他成員函數(shù)那樣被顯式地調(diào)用,它是在定義對(duì)象的同時(shí)被調(diào)用的。

(6) 在聲明類時(shí)如果沒有定義類的構(gòu)造函數(shù),編譯系統(tǒng)就會(huì)在編譯時(shí)自動(dòng)生成一個(gè)默認(rèn)形式的構(gòu)造函數(shù),

(7)?默認(rèn)構(gòu)造函數(shù)是構(gòu)造對(duì)象時(shí)不提供參數(shù)的構(gòu)造函數(shù)。

(8) 除了無參數(shù)構(gòu)造函數(shù)是默認(rèn)構(gòu)造函數(shù)外,帶有全部默認(rèn)參數(shù)值的構(gòu)造函數(shù)也是默認(rèn)構(gòu)造函數(shù)。

(9)?自動(dòng)調(diào)用:構(gòu)造函數(shù)在定義類對(duì)象時(shí)自動(dòng)調(diào)用, 不需用戶調(diào)用,也不能被用戶調(diào)用。在對(duì)象使用前調(diào)用。

(10)?調(diào)用順序:在對(duì)象進(jìn)入其作用域時(shí)(對(duì)象使用前) 調(diào)用構(gòu)造函數(shù)。

1.2 定義構(gòu)造函數(shù)的一般形式

class類名

{

public:

類名(形參表)?;//構(gòu)造函數(shù)的原型

//類的其它成員

};

類名::類名(形參表)//構(gòu)造函數(shù)的實(shí)現(xiàn)

{

//函數(shù)體

}

1.3 利用構(gòu)造函數(shù)創(chuàng)建對(duì)象

(1) 利用構(gòu)造函數(shù)直接創(chuàng)建對(duì)象.其一般形式為:類名 對(duì)象名[(實(shí)參表)];

這里的“類名”與構(gòu)造函數(shù)名相同,“實(shí)參表”是為構(gòu)造函數(shù)提供的實(shí)際參數(shù)。

例2.7 為類Date建立一個(gè)構(gòu)造函數(shù)

#include<iostream.h>

classDate{

public:

Date(inty,intm,intd);//?構(gòu)造函數(shù)

voidsetDate(inty,intm,intd);

voidshowDate();

private:

intyear,?month,?day;

};

Date::Date(inty,intm,intd)//?構(gòu)造函數(shù)的實(shí)現(xiàn)

{?year=y;?month=m;?day=d;?}

voidDate::setDate(inty,intm,intd)

{?year=y;?month=m;?day=d;?}

inlinevoidDate::showDate()

{cout<

例2.8 利用構(gòu)造函數(shù)直接創(chuàng)建對(duì)象

#include<iostream.h>

classDate{

//?省略,?同例2.7

};

//?省略,?同例2.7

voidmain()

{

Datedate1(1998,4,28);//?定義類Date的對(duì)象date1,

//?自動(dòng)調(diào)用date1的構(gòu)造函數(shù),初始化對(duì)象date1

cout<<"Date1?output1:"<

date1.showDate();//?調(diào)用date1的showDate(),顯示date1的數(shù)據(jù)

date1.SetDate(2002,11,14);//?調(diào)用date1的setDate(),

//?重新設(shè)置date1的數(shù)據(jù)

cout<<"Date1?output2:"<

date1.showDate();//?調(diào)用date1的showDate(),顯示date1的數(shù)據(jù)

}

constructing...

Date1output1:

1998.4.28

Date1output2:

2002.11.14

(2) 利用構(gòu)造函數(shù)創(chuàng)建對(duì)象時(shí),通過指針和new來實(shí)現(xiàn)。其一般語法形式為:

類名 *指針變量 = new 類名[(實(shí)參表)];

voidmain()

{

Date?*date1;

date1=newDate(1998,4,28);

//可合寫成:Date?*date1=new?Date(1998,4,28);

cout<<"Date1?output1:"<

date1->showDate();

date1->setDate(2002,11,14);

cout<<"Date1?output2:"<

date1->showDate();

deletedate1;

}

說明:

構(gòu)造函數(shù)的名字必須與類名相同,否則編譯器將把它當(dāng)作一般的成員函數(shù)來處理。

構(gòu)造函數(shù)是不能說明它的返回值類型的,甚至說明為void類型也不行。

構(gòu)造函數(shù)可以是不帶參數(shù)的。

classA{

public:

A();

//…

private:

intx;

};

A∷A()

{

cout<<"initialized?\n";

x=50;

}

main()

{

A?a;

}

有兩個(gè)長(zhǎng)方柱,其長(zhǎng)、寬、高分別為:(1)12,25,30;(2)15,30,21。求它們的體積。要求:編一個(gè)基于對(duì)象的程序,在類中用帶參數(shù)的構(gòu)造函數(shù)。

classBox{

public:

Box(int,int,int);

intvolume(?);

private:

intheight;

intwidth;

intlength;

};

Box::Box(inth,intw,intlen)

{

height?=?h;

width?=?w;

length?=?len;

}

intBox::volume(?)

{

returnheight*width*length;

}

intmain(?)

{

Boxbox1(12,25,30);

cout<<?box1.volume(?)?<

Boxbox2(15,30,21);

cout<<?box2.volume(?)?<

return0;

}

2、成員初始化表

對(duì)于常量類型和引用類型的數(shù)據(jù)成員,不能在構(gòu)造函數(shù)中用賦值語句直接賦值,C++提供初始化表進(jìn)行置初值。

帶有成員初始化表的構(gòu)造函數(shù)的一般形式如下:

類名::構(gòu)造函數(shù)名([參數(shù)表])[:(成員初始化表)]

{

// 構(gòu)造函數(shù)體

}

成員初始化表的一般形式為:

數(shù)據(jù)成員名1(初始值1),數(shù)據(jù)成員名2(初始值2),……

例2.9 成員初始化表的使用

#include<iostream.h>

classA{

public:

A(intx1):x(x1),rx(x),pi(3.14)//?rx(x)相當(dāng)于rx=x,?pi(3.14)相當(dāng)于pi=3.14

{?}

voidprint()

{cout<<"x="<

private:

intx;int&?rx;constfloatpi;

};

main()

{

Aa(10);

a.print();

return0;

}

構(gòu)造函數(shù)采用成員初始化表對(duì)數(shù)據(jù)成員進(jìn)行初始化,是一些程序員喜歡使用的方法。

classB{

inti;

charj;

floatf;

public:

B(intI,charJ,floatF)

{?i=I;?j=J;?f=F;?};

};

classB{

public:

B(intI,charJ,floatF):i(I),j(J),f(F)

{?}

private:

inti;

charj;

floatf;

};

說明

如果需要將數(shù)據(jù)成員存放在堆中或數(shù)組中,則應(yīng)在構(gòu)造函數(shù)中使用賦值語句,即使構(gòu)造函數(shù)有成員初始化表也應(yīng)如此。

classC{

public:

C(int?I,char?Ch,float?F,char?N[]):i(I),ch(Ch),f(F)

{?strcpy?(name,N);}

private:

inti;

charch;

floatf;

charname[25];

};

類成員是按照它們?cè)陬惱锉宦暶鞯捻樞虺跏蓟?與它們?cè)诔跏蓟碇辛谐龅捻樞驘o關(guān)。

【例2.10】

#include<iostream.h>

classD{

public:

D(inti):mem2(i),mem1(mem2+1)

{

cout<<"mem1:?"<

cout<<"mem2:?"<

}

private:

intmem1;

intmem2;

};

voidmain()

{

Dd(15);

}

mem1:?-858993459

mem2:?15

3、缺省參數(shù)的構(gòu)造函數(shù)

例2.11

#include<iostream.h>

classCoord{

public:

Coord(inta=0,intb=0){?x=a;?y=b;}//?帶有缺省參數(shù)的構(gòu)造函數(shù)

intgetx(){returnx;?}

intgety(){returny;?}

private:

intx,y;

};

voidmain()

{

Coordop1(5,6);Coordop2(5);?Coord?op3;

inti,j;

i=op1.getx();j=op1.gety();

cout<<"op1?i=?"<

i=op2.getx();j=op2.gety();

cout<<"op2?i=?"<

i=op3.getx();j=op3.gety();

cout<<"op3?i=?"<

}

classBox{

public:

Box(inth=10,intw=10,intl=10);//在聲明構(gòu)造函數(shù)時(shí)指定默認(rèn)參數(shù)

intvolume(?){return(height*width*length);?}

private:

intheight;

intwidth;

intlength;

};

Box::?Box(inth,intw,intl)//在定義函數(shù)時(shí)可以不指定默認(rèn)參數(shù)

{

height=h;

width=w;

length=l;

}

4、重載構(gòu)造函數(shù)

構(gòu)造函數(shù)的重載

在一個(gè)類中可以定義多個(gè)構(gòu)造函數(shù),以便對(duì)類對(duì)象提供不同的初始化的方法,供用戶選用。這些構(gòu)造函數(shù)具有相同的名字,而參數(shù)的個(gè)數(shù)或參數(shù)的類

型不相同(這稱為構(gòu)造函數(shù)的重載)

關(guān)于構(gòu)造函數(shù)重載的說明

(1)?默認(rèn)構(gòu)造函數(shù):一個(gè)調(diào)用構(gòu)造函數(shù)時(shí)不必給出實(shí)參的構(gòu)造函數(shù)。 顯然,無參的構(gòu)造函數(shù)屬于默認(rèn)構(gòu)造函數(shù)。一個(gè)類只能有一個(gè)默認(rèn)構(gòu)造函數(shù)。

(2) 盡管在一個(gè)類中可以包含多個(gè)構(gòu)造函數(shù),但是對(duì)于每一個(gè)對(duì)象來說,建立對(duì)象時(shí)只執(zhí)行其中一個(gè)構(gòu)造函數(shù),并非每個(gè)構(gòu)造函數(shù)都被執(zhí)行。

classBox{

public:

Box(inth,intw,intl):?height(h),width(w),length(l)?{?}

Box();

intvolume(?);

private:

intheight;

intwidth;

intlength;

};

Box::Box()

{

height?=10;

width?=10;

lenght?=10;

}

intBox::volume(?)

{

returnheight*width*length;

}

intmain(?)

{

Box?box1;//?書上為?box1();

cout<<?box1.volume(?)?<

Boxbox2(15,30,25);

cout<<?box2.volume(?)?<

return0;

}

例2.17 重載構(gòu)造函數(shù)應(yīng)用例程。

#include<iostream.h>

classDate{

public:

Date();//?無參數(shù)的構(gòu)造函數(shù)

Date(inty,intm,intd);//?帶有參數(shù)的構(gòu)造函數(shù)

voidshowDate();

private:

intyear,?month,?day;

};

Date::Date()

{?year=1998;?month=4;?day=28;?}

Date::Date(inty,intm,intd)

{?year=y;?month=m;?day=d;?}

inlinevoidDate::showDate()

{cout<

voidmain()

{

Date?date1;//?聲明類Date的對(duì)象date1,

//?調(diào)用無參數(shù)的構(gòu)造函數(shù)

cout<<"Date1?output:?"<

date1.showDate();//?調(diào)用date1的showDate(),顯示date1的數(shù)據(jù)

Datedate2(2002,11,14);//?定義類Date的對(duì)象date2,

//?調(diào)用帶參數(shù)的構(gòu)造函數(shù)

cout<<"Date2?output:?"<

date2.showDate();//?調(diào)用date2的showDate(),顯示date2的數(shù)據(jù)

}

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

Date1output:

1998.4.28

Date2output:

2002.11.14

例2.18 關(guān)于計(jì)時(shí)器的例子

#include<iostream.h>

#include<stdlib.h>

classtimer{

public:

timer()//?無參數(shù)構(gòu)造函數(shù),給seconds清0

{?seconds=0;?}

timer(char*?t)//?含一個(gè)數(shù)字串參數(shù)的構(gòu)造函數(shù)

{?seconds=atoi(t);?}

timer(intt)//?含一個(gè)整型參數(shù)的構(gòu)造函數(shù)

{?seconds=t;?}

timer(intmin,intsec)//?含兩個(gè)整型參數(shù)的構(gòu)造函數(shù)

{?seconds=min*60+sec;?}

intgettime()

{returnseconds;?}

private:

intseconds;

};

main()

{

timer?a,b(10),c("20"),d(1,10);

cout<<"seconds1="<

cout<<"seconds2="<

cout<<"seconds3="<

cout<<"seconds4="<

return0;

}

classx{

public:

x();//?沒有參數(shù)的構(gòu)造函數(shù)

x(inti=0);//?帶缺省參數(shù)的構(gòu)造函數(shù)

};

//…

voidmain()

{

xone(10);//?正確,調(diào)用x(int?i=0)

x?two;//?存在二義性

//…

}

5、拷貝構(gòu)造函數(shù)

拷貝構(gòu)造函數(shù)是一種特殊的構(gòu)造函數(shù),其形參是本類對(duì)象的引用。其作用是使用一個(gè)已經(jīng)存在的對(duì)象去初始化另一個(gè)同類的對(duì)象。

通過等于號(hào)復(fù)制對(duì)象時(shí),系統(tǒng)會(huì)自動(dòng)調(diào)用拷貝構(gòu)造函數(shù)。

拷貝構(gòu)造函數(shù)與原來的構(gòu)造函數(shù)實(shí)現(xiàn)了函數(shù)的重載。

拷貝構(gòu)造函數(shù)具有以下特點(diǎn):

(1) 因?yàn)樵摵瘮?shù)也是一種構(gòu)造函數(shù),所以其函數(shù)名與類名相同,并且該函數(shù)也沒有返回值類型。

(2) 該函數(shù)只有一個(gè)參數(shù),并且是同類對(duì)象的引用。

(3) 每個(gè)類都必須有一個(gè)拷貝構(gòu)造函數(shù)。程序員可以根據(jù)需要定義特定的拷貝構(gòu)造函數(shù),以實(shí)現(xiàn)同類對(duì)象之間數(shù)據(jù)成員的傳遞。如果程序員沒有定義類的拷貝構(gòu)造函數(shù),系統(tǒng)就會(huì)自動(dòng)生成產(chǎn)生一個(gè)缺省的拷貝構(gòu)造函數(shù)。

5.1 自定義拷貝構(gòu)造函數(shù)

自定義拷貝構(gòu)造函數(shù)的一般形式如下:

class類名{

public:

類名(形參);//構(gòu)造函數(shù)

類名(類名?&對(duì)象名);//拷貝構(gòu)造函數(shù)

...

};

類名::?類名(類名?&對(duì)象名)//拷貝構(gòu)造函數(shù)的實(shí)現(xiàn)

{?函數(shù)體?}

用戶自定義拷貝構(gòu)造函數(shù)

classCoord{

intx,y;

public:

Coord(inta,intb)//?構(gòu)造函數(shù)

{

x=a;

y=b;

cout<<"Using?normal?constructor\n";

}

Coord(constCoord&?p)//?拷貝構(gòu)造函數(shù)

{

x=2*p.x;

y=2*p.y;

cout<<"Using?copy?constructor\n";

}

//…

};

如果p1、 p2為類Coord的兩個(gè)對(duì)象,p1已經(jīng)存在,則coord p2(p1)調(diào)用拷貝構(gòu)造函數(shù)來初始化p2

例2.19 自定義拷貝構(gòu)造函數(shù)的使用

#include<iostream.h>

classCoord{

public:

Coord(inta,intb)//?構(gòu)造函數(shù)

{?x=a;?y=b;cout<<"Using?normal?constructor\n";}

Coord(constCoord&?p)//?拷貝構(gòu)造函數(shù)

{?x=2*p.x;?y=2*p.y;cout<<"Using?copy?constructor\n";}

voidprint(){cout<

private:

intx,y;

};

main()

{

Coordp1(30,40);//?定義對(duì)象p1,調(diào)用了普通的構(gòu)造函數(shù)

Coordp2(p1);//?以“代入”?法調(diào)用拷貝構(gòu)造函數(shù),用對(duì)象p1初始化對(duì)象p2

p1.print();

p2.print();

return0;

}

除了用代入法調(diào)用拷貝構(gòu)造函數(shù)外,還可以采用賦值法調(diào)用拷貝構(gòu)造函數(shù),如:

main()

{

Coordp1(30,40);

Coord?p2=p1;//以"賦值"法調(diào)用拷貝構(gòu)造函數(shù),

用對(duì)象p1初始化對(duì)象p2

//…

}

5.2 缺省的拷貝構(gòu)造函數(shù)

如果沒有編寫自定義的拷貝構(gòu)造函數(shù),C++會(huì)自動(dòng)地將一個(gè)已存在的對(duì)象復(fù)制給新對(duì)象,這種按成員逐一復(fù)制的過程由是缺省拷貝構(gòu)造函數(shù)自動(dòng)完成的。

例2.20 調(diào)用缺省的拷貝構(gòu)造函數(shù)

#include<iostream.h>

classCoord{

public:

Coord(inta,intb)

{?x=a;?y=b;cout<<"Using?normal?constructor\n";?}

voidprint(){cout<

private:

intx,y;

};

main()

{

Coordp1(30,40);//?定義類Coord的對(duì)象p1,

//?調(diào)用了普通構(gòu)造函數(shù)初始化對(duì)象p1

Coordp2(p1);//?以“代入”法調(diào)用缺省的拷貝構(gòu)造函數(shù),

//?用對(duì)象p1初始化對(duì)象p2

Coord?p3=p1;//?以“賦值”法調(diào)用缺省的拷貝構(gòu)造函數(shù),

//?用對(duì)象p1初始化對(duì)象p3

p1.print();?p2.print();?p3.print();

return0;

}

5.3 調(diào)用拷貝構(gòu)造函數(shù)的三種情況

(1) 當(dāng)用類的一個(gè)對(duì)象去初始化該類的另一個(gè)對(duì)象時(shí)。

Coordp2(p1);//?用對(duì)象p1初始化對(duì)象p2,?拷貝構(gòu)造函數(shù)被調(diào)用(代入法)

Coord?p3=p1;//?用對(duì)象p1初始化對(duì)象p3,?拷貝構(gòu)造函數(shù)被調(diào)用(賦值法)

(2) 當(dāng)函數(shù)的形參是類的對(duì)象,調(diào)用函數(shù),進(jìn)行形參和實(shí)參結(jié)合時(shí)。

//…

fun1(Coord?p)//?函數(shù)的形參是類的對(duì)象

{

p.print();

}

main()

{

Coordp1(10,20);

fun1(p1);//?當(dāng)調(diào)用函數(shù),進(jìn)行形參和實(shí)參結(jié)合時(shí),

調(diào)用拷貝構(gòu)造函數(shù)

return0;

}

(3) 當(dāng)函數(shù)的返回值是對(duì)象,函數(shù)執(zhí)行完成,返回調(diào)用者時(shí)。

//?…

Coordfun2()

{

Coordp1(10,30);

returnp1;

}//?函數(shù)的返回值是對(duì)象

main()

{

Coord?p2;

P2=fun2();//?函數(shù)執(zhí)行完成,返回調(diào)用者時(shí),調(diào)用拷貝構(gòu)造函數(shù)

return0;

}

5.4 淺拷貝和深拷貝

所謂淺拷貝,就是由缺省的拷貝構(gòu)造函數(shù)所實(shí)現(xiàn)的數(shù)據(jù)成員逐一賦值,若類中含有指針類型數(shù)據(jù), 則會(huì)產(chǎn)生錯(cuò)誤。

為了解決淺拷貝出現(xiàn)的錯(cuò)誤,必須顯示地定義一個(gè)自己的拷貝構(gòu)造函數(shù),使之不但拷貝數(shù)據(jù)成員,而且為對(duì)象1和對(duì)象2分配各自的內(nèi)存空間,這就是所謂的深拷貝。

例2.23 淺拷貝例子

#include<iostream.h>

#include<string.h>

classStudent{

public:

Student(char*name1,floatscore1);

~Student();

private:

char*name;//?學(xué)生姓名

floatscore;//?學(xué)生成績(jī)

};

Student∷Student(char*name1,floatscore1)

{

cout<<"Constructing..."<

name=newchar[strlen(name1)+1];

if(name?!=0)

{

strcpy(name,name1);

score=score1;

}

}

Student∷~Student()

{

cout<<"Destructing..."<

name[0]='\0';

deletename;

}

voidmain()

{

Studentstu1("liming",90);//?定義類Student的對(duì)象stu1

Student?stu2=stu1;//?調(diào)用缺省的拷貝構(gòu)造函數(shù)

}

Constructing...?liming

Destructing...?liming

Destructing...

淺拷貝示意圖

例2.24 深拷貝例子

#include<iostream.h>

#include<string.h>

classStudent{

private:

char*name;//?學(xué)生姓名

floatscore;//?學(xué)生成績(jī)

public:

Student(char*name1,floatscore1);

Student(Student&?stu);

~Student();

};

Student∷Student(char*name1,floatscore1)

{

cout<<"constructing..."<

name=newchar[strlen(name1)+1];

if(name?!=0)

{

strcpy(name,name1);

score=score1;

}

}

Student∷Student(Student&?stu)

{

cout<<"Copy?constructing..."<

name=newchar[strlen(stu.name)+1];

if(name?!=0)

{

strcpy(name,stu.name);

score=stu.score;

}

}

Student∷~Student()

{

cout<<"Destructing..."<

name[0]='\0';

deletename;

}

voidmain()

{

Studentstu1("liming",90);//?定義類Student的對(duì)象stu1,

Student?stu2=stu1;//?調(diào)用自定義的拷貝構(gòu)造函數(shù)

}

深拷貝示意圖

6、析構(gòu)函數(shù)

析構(gòu)函數(shù)也是一種特殊的成員函數(shù)。它執(zhí)行與構(gòu)造函數(shù)相反的操作,通常用于撤消對(duì)象時(shí)的一些清理任務(wù),如釋放分配給對(duì)象的內(nèi)存空間等。

析構(gòu)函數(shù)有以下一些特點(diǎn):

① 析構(gòu)函數(shù)與構(gòu)造函數(shù)名字相同,但它前面必須加一個(gè)波浪號(hào)(~);

② 析構(gòu)函數(shù)沒有參數(shù),也沒有返回值,而且不能重載。因此在一個(gè)類中只能有一個(gè)析構(gòu)函數(shù);

③ 當(dāng)撤消對(duì)象時(shí),編譯系統(tǒng)會(huì)自動(dòng)地調(diào)用析構(gòu)函數(shù)。 如果程序員沒有定義析構(gòu)函數(shù),系統(tǒng)將自動(dòng)生成和調(diào)用一個(gè)默認(rèn)析構(gòu)函數(shù),默認(rèn)析構(gòu)函數(shù)只能釋放對(duì)象的數(shù)據(jù)成員所占用的空間,但不包括堆內(nèi)存空間。

例2.25 重新說明類Date

#include<iostream.h>

classDate{

public:

Date(inty,intm,intd);//?構(gòu)造函數(shù)

~Date();//?析構(gòu)函數(shù)

voidsetDate(inty,intm,intd);

voidshowDate();

private:

intyear,?month,?day;

};

Date::Date(inty,intm,intd)//?構(gòu)造函數(shù)的實(shí)現(xiàn)

{

cout<<"constructing..."<

year=y;month=m;?day=d;

}

Date::~Date()//?析構(gòu)函數(shù)的實(shí)現(xiàn)

{cout<<"destruting..."<

voidDate::setDate(inty,intm,intd)

{?year=y;month=m;day=d;?}

inlinevoidDate::showDate()

{cout<

voidmain()

{

Datedate1(1998,4,28);//?定義類Date的對(duì)象date1,

//?調(diào)用date1的構(gòu)造函數(shù),初始化對(duì)象date1

cout<<"Date1?output1:"<

date1.showDate();//?調(diào)用date1的showDate(),顯示date1的數(shù)據(jù)

date1.setDate(2002,11,14);//?調(diào)用date1的setDate(),

//?重新設(shè)置date1的數(shù)據(jù)

cout<<"Date1?output2:"<

date1.showDate();//?調(diào)用date1的showDate(),顯示date1的數(shù)據(jù)

}

析構(gòu)函數(shù)被調(diào)用的兩種情況

1) 若一個(gè)對(duì)象被定義在一個(gè)函數(shù)體內(nèi),當(dāng)這個(gè)函數(shù)結(jié)束時(shí),析構(gòu)函數(shù)被自動(dòng)調(diào)用。

2) 若一個(gè)對(duì)象是使用new運(yùn)算符動(dòng)態(tài)創(chuàng)建,在使用delete釋放時(shí),自動(dòng)調(diào)用析構(gòu)函數(shù)。

【例2.13】 較完整的學(xué)生類例子

#include<iostream.h>

#include<string.h>

classStudent{

public:

Student(char*name1,char*stu_no1,floatscore1);//?構(gòu)造

函數(shù)

~Student();//?析構(gòu)函數(shù)

voidmodify(floatscore1);//?修改數(shù)據(jù)

voidshow();//?顯示數(shù)據(jù)

private:

char*name;//?學(xué)生姓名

char*stu_no;//?學(xué)生學(xué)號(hào)

floatscore;//?學(xué)生成績(jī)

};

Student∷Student(char*name1,char*stu_no1,floatscore1)

{

name=newchar[strlen(name1)+1];

strcpy(name,name1);

stu_no=newchar[strlen(stu_no1)+1];

strcpy(stu_no,stu_no1);

score=score1;

}

Student∷~Student()

{

delete[]name;

delete[]stu_no;

}

voidStudent∷modify(floatscore1)

{?score=score1;?}

voidStudent∷show()

{

cout<<"\n?name:?"<

cout<<"\n?stu_no:?"<

cout<<"\n?score:?"<

}

voidmain()

{

Studentstu1("Liming","990201",90);//?定義類Student的對(duì)象stu1,

//?調(diào)用stu1的構(gòu)造函數(shù),初始化對(duì)象stu1

stu1.show();//?調(diào)用stu1的show(),顯示stu1的數(shù)據(jù)

stu1.modify(88);//?調(diào)用stu1的modify(),修改stu1的數(shù)據(jù)

stu1.show();//?調(diào)用stu1的show(),顯示stu1修改后的數(shù)據(jù)

}

ame:Liming

stu_no:990201

score:90

name:Liming

stu_no:990201

score:88

缺省的析構(gòu)函數(shù)

每個(gè)類必須有一個(gè)析構(gòu)函數(shù)。

若沒有顯式地為一個(gè)類定義析構(gòu)函數(shù),編譯系統(tǒng)會(huì)自動(dòng)地生成一個(gè)缺省的析構(gòu)函數(shù)

其格式如下:類名::析構(gòu)函數(shù)名( ){ }

classstring_data{

public:

string_data(char*)

{?str=newchar[max_len];}

~string_data()

{delete[]str;}

voidget_info(char*);

voidsent_info(char*);

private:

char*str;

intmax_len;

};

7、調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)的順序

1) 一般順序

調(diào)用析構(gòu)函數(shù)的次序正好與調(diào)用構(gòu)造函數(shù)的次序相反:最先被調(diào)用的構(gòu)造函數(shù),其對(duì)應(yīng)的(同一對(duì)象中的)析構(gòu)函數(shù)最后被調(diào)用,而最后被調(diào)用的構(gòu)造函數(shù),其對(duì)應(yīng)的析構(gòu)函數(shù)最先被調(diào)用。

2) 全局對(duì)象

在全局范圍中定義的對(duì)象(即在所有函數(shù)之外定義的對(duì)象),它的構(gòu)造函數(shù)在所有函數(shù)(包括main函數(shù))執(zhí)行之前調(diào)用。在程序的流程離開其作用域時(shí)(如main函數(shù)結(jié)束或調(diào)用exit函數(shù))時(shí),調(diào)用該全局對(duì)象的析構(gòu)函數(shù)。

3) auto局部對(duì)象

局部自動(dòng)對(duì)象(例如在函數(shù)中定義的對(duì)象),則在建立對(duì)象時(shí)調(diào)用其構(gòu)造函數(shù)。如果函數(shù)被多次調(diào)用,則在每次建立對(duì)象時(shí)都要調(diào)用構(gòu)造函數(shù)。在函數(shù)調(diào)用結(jié)束、對(duì)象釋放時(shí)先調(diào)用析構(gòu)函數(shù)。

4) static局部對(duì)象

如果在函數(shù)中定義靜態(tài)局部對(duì)象,則只在程序第一次調(diào)用此函數(shù)建立對(duì)象時(shí)調(diào)用構(gòu)造函數(shù)一次,在調(diào)用結(jié)束時(shí)對(duì)象并不釋放,因此也不調(diào)用析構(gòu)函數(shù),只在main函數(shù)結(jié)束或調(diào)用exit函數(shù)結(jié)束程序時(shí),才調(diào)用析構(gòu)函數(shù)。

8. 對(duì)象的生存期

對(duì)象按生存期的不同分為如下幾種:

(1) 局部對(duì)象

當(dāng)對(duì)象被定義時(shí),調(diào)用構(gòu)造函數(shù),該對(duì)象被創(chuàng)建;當(dāng)程序退出該對(duì)象所在的函數(shù)體或程序塊時(shí),調(diào)用析構(gòu)函數(shù),對(duì)象被釋放。

局部對(duì)象是被定義在一個(gè)函數(shù)體或程序塊內(nèi)的,它的作用域限定在函數(shù)體或程序塊內(nèi),生存期較短。

(2) 全局對(duì)象

當(dāng)程序開始運(yùn)行時(shí),調(diào)用構(gòu)造函數(shù),該對(duì)象被創(chuàng)建;當(dāng)程序結(jié)束時(shí),調(diào)用析構(gòu)函數(shù),該對(duì)象被釋放。

靜態(tài)對(duì)象是被定義在一個(gè)文件中,它的作用域從定義是起到文件結(jié)束時(shí)為止。生存期較長(zhǎng)。

(3) 靜態(tài)對(duì)象

當(dāng)程序中定義靜態(tài)對(duì)象時(shí),調(diào)用構(gòu)造函數(shù),該對(duì)象被創(chuàng)建;當(dāng)整個(gè)程序結(jié)束時(shí),調(diào)用析構(gòu)函數(shù),對(duì)象被釋放。

全局對(duì)象是被定義在某個(gè)文件中,它的作用域包含在該文件的整個(gè)程序中,生存期是最長(zhǎng)的。

(4) 動(dòng)態(tài)對(duì)象

執(zhí)行new運(yùn)算符調(diào)用構(gòu)造函數(shù),動(dòng)態(tài)對(duì)象被創(chuàng)建;用delete釋放對(duì)象時(shí),調(diào)用析構(gòu)函數(shù)。

動(dòng)態(tài)對(duì)象是由程序員掌握的,它的作用域和生存期是由new和delete之間的間隔決定的。

類的應(yīng)用舉例(例)

一圓形游泳池如圖所示,現(xiàn)在需在其周圍建一圓形過道,并在其四周圍上柵欄。柵欄價(jià)格為35元/米,過道造價(jià)為20元/平方米。過道寬度為3米,游泳池半徑由鍵盤輸入。要求編程計(jì)算并輸出過道和柵欄的造價(jià)。

#include<iostream>

usingnamespacestd;

constfloatPI?=3.14159;

constfloatFencePrice?=35;

constfloatConcretePrice?=20;

//聲明類Circle?及其數(shù)據(jù)和方法

classCircle{

private:

floatradius;

public:

Circle(floatr);//構(gòu)造函數(shù)

floatCircumference()const;//圓周長(zhǎng)

/*函數(shù)后的修飾符const表示該成員函數(shù)的執(zhí)行不會(huì)改變類的狀態(tài),也就是說不會(huì)修改類的數(shù)據(jù)成員。?*/

floatArea()const;//圓面積

};//?類的實(shí)現(xiàn)

//?構(gòu)造函數(shù)初始化數(shù)據(jù)成員radius

Circle::Circle(floatr)

{

radius=r;

}

//?計(jì)算圓的周長(zhǎng)

floatCircle::Circumference()const

{

return2*?PI?*?radius;

}

//?計(jì)算圓的面積

floatCircle::Area()const

{

returnPI?*?radius?*?radius;

}

voidmain()

{

floatradius;

floatFenceCost,?ConcreteCost;

//?提示用戶輸入半徑

cout<<"Enter?the?radius?of?the?pool:?";

cin>>radius;

//?聲明?Circle?對(duì)象

CirclePool(radius);

CirclePoolRim(radius?+3);

//計(jì)算柵欄造價(jià)并輸出

FenceCost=PoolRim.Circumference()*FencePrice;

cout<<"Fencing?Cost?is?¥"<

//計(jì)算過道造價(jià)并輸出

ConcreteCost=(PoolRim.Area()-

Pool.Area())*ConcretePrice;

cout<<"Concrete?Cost?is?¥"<

}

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

Enter?the?radiusofthe?pool:10

Fencing?Costis¥2858.85

Concrete?Costis¥4335.39

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 參考鏈接 一、構(gòu)造函數(shù) C++規(guī)定,每個(gè)類必須有默認(rèn)的構(gòu)造函數(shù),沒有構(gòu)造函數(shù)就不能創(chuàng)建對(duì)象。 若沒有提供任何構(gòu)造函...
    Mitchell閱讀 2,704評(píng)論 0 4
  • 構(gòu)造函數(shù) 一.構(gòu)造函數(shù)的作用: 構(gòu)造函數(shù)主要用于來對(duì)類的對(duì)象生成標(biāo)識(shí)符,對(duì)數(shù)據(jù)成員進(jìn)行初始化,和分配內(nèi)存空間。 相...
    loveforkeeps閱讀 484評(píng)論 0 1
  • 構(gòu)造函數(shù) 每個(gè)類分別定義了對(duì)象被初始化的方式,類通過一個(gè)或幾個(gè)特殊的成員函數(shù)來控制對(duì)象的初始化過程,這些函數(shù)叫做構(gòu)...
    Kai_Z閱讀 376評(píng)論 0 1
  • 轉(zhuǎn):C++繼承中構(gòu)造函數(shù)、析構(gòu)函數(shù)調(diào)用順序及虛析構(gòu)函數(shù) 1.構(gòu)造函數(shù) 大家都知道構(gòu)造函數(shù)里就可以調(diào)用成員變量,而繼...
    資深小夏閱讀 831評(píng)論 0 0
  • 心靈自由寫作11篇 “大學(xué)生祼貸”,說實(shí)在的,剛看到這個(gè)主題,心里一點(diǎn)概念都沒有,雖然在新聞上也看到這方面的報(bào)道,...
    庭誼閱讀 1,959評(píng)論 0 0

友情鏈接更多精彩內(nèi)容