類和對象及其封裝性_第1頁
類和對象及其封裝性_第2頁
類和對象及其封裝性_第3頁
類和對象及其封裝性_第4頁
類和對象及其封裝性_第5頁
已閱讀5頁,還剩138頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

類和對象及其封裝性第1頁,共143頁,2023年,2月20日,星期四本章要點

1類的定義及其類對象的封裝性

2類成員函數(shù)的定義

3類對象的定義和使用

4類的構(gòu)造函數(shù)和析構(gòu)函數(shù)

5類對象的動態(tài)創(chuàng)建和釋放

6類對象的賦值與復(fù)制

7與類對象有關(guān)的指針

8類的靜態(tài)成員

9類對象成員、類對象數(shù)組和類對象參數(shù)

10友元(友元函數(shù)、友元成員和友元類)

11類的只讀成員函數(shù)定義第2頁,共143頁,2023年,2月20日,星期四3.1類的定義及其類對象的封裝性無論采用哪種程序設(shè)計范型所設(shè)計的程序都是由數(shù)據(jù)處理這些數(shù)據(jù)的操作組成的。程序的運(yùn)行就是按照特定的結(jié)構(gòu)和流程將操作施加在相應(yīng)的數(shù)據(jù)上,完成程序需要實現(xiàn)的功能。在傳統(tǒng)設(shè)計范型中,數(shù)據(jù)是使用語言所提供的簡單數(shù)據(jù)類型和構(gòu)造數(shù)據(jù)類型(例如C語言中的結(jié)構(gòu)類型

struct)定義生成的;而操作是通過過程或函數(shù)的形式定義提供的。第3頁,共143頁,2023年,2月20日,星期四在面向?qū)ο笤O(shè)計范型中,使用了數(shù)據(jù)抽象的概念,即數(shù)據(jù)總是與允許施加它們的操作綁定在一起的。這就要求編程語言能夠提供符合數(shù)據(jù)抽象的預(yù)定義數(shù)據(jù)類型,特別需要提供能構(gòu)造符合數(shù)據(jù)抽象用戶自定義類型的構(gòu)造數(shù)據(jù)類型(例如C++

和Java

語言中的類類型class)。程序中的數(shù)據(jù)和操作都是由按數(shù)據(jù)抽象封裝起來的對象提供的。第4頁,共143頁,2023年,2月20日,星期四3.1.1C++的類類型定義

在C++中,用戶可以使用類類型關(guān)鍵字

class定義自己的抽象數(shù)據(jù)類型。這種定義方法和形式與使用結(jié)構(gòu)體類型關(guān)鍵字struct定義數(shù)據(jù)結(jié)構(gòu)類型十分相似。例如,可以用struct定義描述學(xué)生基本信息的數(shù)據(jù)結(jié)構(gòu)類型Student:

struct

Student { intnum; charname[20]; charsex; };第5頁,共143頁,2023年,2月20日,星期四同樣,可以用class定義描述學(xué)生基本信息和基本操作的數(shù)據(jù)類型Student:

class

Student

{ intnum; charname[20]; charsex;

public: voiddisplay() { cout<<“num:”<<num<<endl; cout<<“name:”<<name<<endl; cout<<“sex:”<<sex<<endl; } };第6頁,共143頁,2023年,2月20日,星期四比較兩種用戶自定義類型,它們的共同之處表現(xiàn)在:⑴類型定義首行的格式相同,由類型關(guān)鍵字(struct

class)與自定義類名組成。例如:“structStudent”和“classStudent”。⑵類型定義體都使用左花括號“{”表示開始,使用右花括號“}”表示結(jié)束,并用分號“;”表示整個自定義類型定義工作完成。⑶使用自定義類型(結(jié)構(gòu)或類)定義類型實體(結(jié)構(gòu)

變量或類對象)的格式相同。在面向?qū)ο蟮某绦蛟O(shè)計中通常將所有的類型(包括系統(tǒng)預(yù)定義的簡單數(shù)據(jù)類型)實體可以統(tǒng)一稱為對象。例如,可使用自定義結(jié)構(gòu)類型Student定義結(jié)構(gòu)對象:

Studentstud1,stud2;

也可使用自定義類類型Student定義類對象:

Studentstud1,stud2;第7頁,共143頁,2023年,2月20日,星期四在面向?qū)ο蟮某绦蛟O(shè)計中通常將所有的類型(包括系統(tǒng)預(yù)定義的簡單數(shù)據(jù)類型)實體可以統(tǒng)一稱為對象。例如,可使用自定義結(jié)構(gòu)類型Student定義結(jié)構(gòu)對象:

Studentstud1,stud2;

也可使用自定義類類型Student定義類對象:

Studentstud1,stud2;第8頁,共143頁,2023年,2月20日,星期四二者的不同之處表現(xiàn)在:⑴使用C

語言的struct

定義的結(jié)構(gòu)類型的定義體中只包含數(shù)據(jù)成員,而使用class定義類類型的定義體中既包含數(shù)據(jù)成員,還包含了操作這些數(shù)據(jù)的成員函數(shù)。注意,在C++

中,struct

定義能力被擴(kuò)展,也可以class定義一樣包含操作數(shù)據(jù)成員的成員函數(shù)。⑵結(jié)構(gòu)類型的成員的缺省訪問權(quán)限均為公有,即可以從結(jié)構(gòu)對象外直接訪問。例如:

Studentstud1; cout<<“num:”<<stud1.num<<endl;第9頁,共143頁,2023年,2月20日,星期四

cout<<“name:”<<<<endl; cout<<“sex:”<<stud1.sex<<endl;

而類類型的成員的缺省訪問權(quán)限均為私有,例如,類Student

中的數(shù)據(jù)成員就不能從類外直接訪問,而顯示這些數(shù)據(jù)只能通過調(diào)用成員函數(shù)

display實現(xiàn)。

Studentstud1; cout<<“name:”<<<<endl;//非法

stud1.display();第10頁,共143頁,2023年,2月20日,星期四3.1.2類類型成員的訪問權(quán)限為了實現(xiàn)類對象的封裝性(數(shù)據(jù)隱藏和提供訪問接口)類類型定義為類成員提供了私有和公有兩種基本訪問權(quán)限供用戶選擇。1私有成員①訪問權(quán)限:只限于類成員訪問。②關(guān)鍵字:private聲明或從定義體開始的缺省聲明。例如,下面的Student定義與前面的Student

定義等價的:第11頁,共143頁,2023年,2月20日,星期四

class

Student {

private: intnum; charname[20]; charsex;

public: voiddisplay(){ cout<<“num:”<<num<<endl; cout<<“name:”<<name<<endl; cout<<“sex:”<<sex<<endl; } };第12頁,共143頁,2023年,2月20日,星期四③私有段:從private:

開始至其它訪問權(quán)限聲明之間 所有成員組成的代碼段。例如Student

定義中從

private:

開始到public:

之間的所數(shù)據(jù)成員。④成員種類:數(shù)據(jù)成員和成員函數(shù)。2公有成員①訪問權(quán)限:允許類成員和類外的任何訪問。②關(guān)鍵字:public。③公有段:從public:

至其它成員聲明之間所有成員 組成的代碼段。④成員種類:數(shù)據(jù)成員和成員函數(shù)。第13頁,共143頁,2023年,2月20日,星期四使用私有成員來隱藏由類對象操作的數(shù)據(jù),然后提供相應(yīng)的公有成員函數(shù)來訪問和操作這些數(shù)據(jù),而訪問和操作這些數(shù)據(jù)實現(xiàn)細(xì)節(jié)通常是被隱藏起來的。除了私有和公有兩種基本訪問權(quán)限外,類類型定義還提供了允許類成員和派生類成員訪問,而不允許類外訪問的保護(hù)成員訪問權(quán)限(protected),以滿足實現(xiàn)繼承性的需要。第14頁,共143頁,2023年,2月20日,星期四為了使C++

語言所設(shè)計程序中的數(shù)據(jù)都能實現(xiàn)數(shù)據(jù)抽象,并能與C

語言設(shè)計的程序中的數(shù)據(jù)兼容,C++

仿照類類型定義的功能,對struct

定義的結(jié)構(gòu)體類型功能進(jìn)行如下擴(kuò)展:⑴定義體中也可以包括對數(shù)據(jù)成員進(jìn)行處理和操作的

成員函數(shù)。⑵添加了與類類型定義相同的成員訪問權(quán)限聲明功能,但仍然保留了缺省聲明表示成員的訪問權(quán)限為

公用的基本特點。擴(kuò)展后的struct

可以定義與類類型效果相同的結(jié)構(gòu)類型,例如:第15頁,共143頁,2023年,2月20日,星期四

struct

Student {

private: intnum; charname[20]; charsex;

public: voiddisplay(){ cout<<“num:”<<num<<endl; cout<<“name:”<<name<<endl; cout<<“sex:”<<sex<<endl; } };第16頁,共143頁,2023年,2月20日,星期四該結(jié)構(gòu)類型與先前使用class

定義的Student

類型的效果完全相同。請注意,這并不意味著可以用struct

替代class,因為使用class定義的類類型的缺省私有性質(zhì)能更方便、安全地實現(xiàn)面向?qū)ο蟪绦蛟O(shè)計對類對象的要求,因此強(qiáng)烈建議使用class建立數(shù)據(jù)類型;而只有希望所建立類型的全部成員都是公有訪問權(quán)限時,使用struct建立結(jié)構(gòu)類型比較方便。第17頁,共143頁,2023年,2月20日,星期四3.1.3類類型的構(gòu)造

類類型定義為所定義的數(shù)據(jù)類型建立了一個明確的邊界,類定義體中的私有成員(數(shù)據(jù)成員和成員函數(shù))和公有成員函數(shù)的實現(xiàn)細(xì)節(jié)均被封裝在此邊界內(nèi),使得這些類成員和實現(xiàn)細(xì)節(jié)無法從類對象外被訪問,從而受到保護(hù)。同時對類公有成員(數(shù)據(jù)成員和成員函數(shù))的訪問和調(diào)用又為類對象之間的通訊提供了接口,使得類對象成為一個既訪問安全又操作方便的抽象數(shù)據(jù)實體。下面以一個簡單機(jī)器人類為例說明類類型的構(gòu)造:第18頁,共143頁,2023年,2月20日,星期四①確定機(jī)器人狀態(tài)的屬性:是位置和面對的方向②改變、訪問和顯示機(jī)器人狀態(tài)的操作:有定位、

轉(zhuǎn)向、前進(jìn)、顯示狀態(tài)等。

classHominoid { intdirction; //機(jī)器人的方向

pointlocation; //機(jī)器人的位置

public: voidturnLeft(); //向左轉(zhuǎn)90度

voidturnRight(); //向右轉(zhuǎn)90度

booladvance(); //前進(jìn)一步

pointlocation(pointloc); //定位

boolfacingWall(); //判斷是否面對墻壁

voiddisplay(); //顯示當(dāng)前位置

… };第19頁,共143頁,2023年,2月20日,星期四

booladvance(); //前進(jìn)一步

pointlocation(pointloc); //定位

boolfacingWall(); //判斷是否面對墻壁

voiddisplay(); //顯示當(dāng)前位置

… };

該定義所建立的機(jī)器人類的構(gòu)造可以形象地用下圖 表示,它很象一個封裝好的器件。第20頁,共143頁,2023年,2月20日,星期四directionlocation...turnLeftdislayturnRightfacingWalladvancelocation屬性操作邊界第21頁,共143頁,2023年,2月20日,星期四

Java

的類定義與C++

的類定義在格式上基本相同,但有兩點是不一樣的:⑴成員的訪問權(quán)限必須逐個顯式說明;⑵類定義結(jié)束不要分號“;”。例如:

classUser

{

privateStringname;

privateintage;

publicUser(Stringstrintyy){name=str;age=yy;} } 返回第22頁,共143頁,2023年,2月20日,星期四3.2類成員函數(shù)的定義1成員函數(shù)的性質(zhì)類的成員函數(shù)在聲明和定義的格式上以及用法和作用上與一般函數(shù)基本一致。但由于成員函數(shù)是屬于某一個類的成員,因此它與一般函數(shù)的區(qū)別表現(xiàn):⑴作用域在類定義體所確定的邊界內(nèi),即可以訪問本類的任何成員(私有和公有的數(shù)據(jù)和函數(shù))。⑵需要根據(jù)功能和作用指定成員函數(shù)的訪問權(quán)限,一般情況下,將向類外提供操作功能的成員函數(shù)指定為public,將只為類內(nèi)提供服務(wù)功能的成員函數(shù)指定為private,將只為類內(nèi)和派生類提供服務(wù)功能的成員函數(shù)指定為protected。第23頁,共143頁,2023年,2月20日,星期四2成員函數(shù)的聲明和定義形式

⑴在類定義體內(nèi)定義成員函數(shù)的實現(xiàn)代碼。這種形 式下,函數(shù)定義的首部將起到函數(shù)原型的作用, 因此無須成員函數(shù)定義之前的原型聲明。例如: classpoint

{ intx,y; public: voidsetpoint(intvx,intvy) {x=vx;y=vy;} };第24頁,共143頁,2023年,2月20日,星期四

⑵在類定義體內(nèi)聲明成員函數(shù),而在類定義體外定 義成員函數(shù)的實現(xiàn)代碼。采用這種定義形式的 時,類定義體外的定義代碼必須滿足:

①在成員函數(shù)名之前應(yīng)綴上所屬的類名::,“::”是 作用域運(yùn)算符,以便說明函數(shù)的作用域。②成員函數(shù)定義的首部(函數(shù)的返回類型、函數(shù) 名和參數(shù)表列)必須與在類定義體中聲明的該 函數(shù)的原型一致。例如:第25頁,共143頁,2023年,2月20日,星期四 classpoint{ intx,y; public: voidsetpoint(int,int); }; voidpoint::setpoint(intvx,intvy) { x=vx; y=vy; }由于第⑵種形式不僅可以減少類定義體的代碼長度,使類定義體清晰、可讀性好;更重要的是有助 于類的操作接口與操作實現(xiàn)細(xì)節(jié)相分離,并隱藏細(xì) 節(jié)。因此,提倡采用該形式定義類成員函數(shù)。第26頁,共143頁,2023年,2月20日,星期四3類的內(nèi)置(內(nèi)聯(lián))成員函數(shù)定義方式:

⑴隱式定義——函數(shù)定義在類定義體中,此時只要函數(shù)的實現(xiàn)代碼符合內(nèi)置函數(shù)的定義要求,該成員函數(shù)就會自動被定義內(nèi)置函數(shù),而說明內(nèi)置函數(shù)的關(guān)鍵字inline可以忽略。例如: classpoint

{ intx,y; public: voidsetpoint(intvx,intvy) //內(nèi)置函數(shù) {x=vx;y=vy;} };其中成員函數(shù)setpoint定義的首部與加綴inline的首部“inlinevoidsetpoint(intvx,intvy)”等效。第27頁,共143頁,2023年,2月20日,星期四

⑵顯式定義——函數(shù)聲明在類定義體中,而函數(shù)定義在類定義體外,此時函數(shù)定義的首部必須冠以關(guān)鍵字inline說明此函數(shù)是內(nèi)置的。例如: classpoint { intx,y; public:

inlinevoidsetpoint(int,int); //內(nèi)置函數(shù)聲明 };

inlinevoidpoint::setpoint(intvx,intvy)//內(nèi)置函數(shù)定義 { x=vx; y=vy; }第28頁,共143頁,2023年,2月20日,星期四需要特別注意的是:由于調(diào)用內(nèi)置函數(shù)需要將內(nèi)置函數(shù)的目標(biāo)代碼復(fù)制到它被調(diào)用的位置,因此編譯器在進(jìn)行內(nèi)置函數(shù)的調(diào)用編譯時,必須能獲得被調(diào)內(nèi)置函數(shù)的目標(biāo)代碼。這就需要在調(diào)用內(nèi)置函數(shù)的源代碼文件中必須包含被調(diào)用內(nèi)置函數(shù)的定義代碼的源代碼文件。也就是說,如果某個被調(diào)用的內(nèi)置成員函數(shù)定義在類定義體中,該類定義體代碼被保存在一個頭文件中,例如“student.h”,則調(diào)用該內(nèi)置函數(shù)的源文件應(yīng)添加預(yù)編譯命令#include“student.h”。如果該內(nèi)置函數(shù)定義在類定義體外,代碼包含在類實現(xiàn)文件中,例如“student.cpp”,則調(diào)用該內(nèi)置函數(shù)的源文件應(yīng)添加預(yù)編譯命令#include“student.cpp”。第29頁,共143頁,2023年,2月20日,星期四4成員函數(shù)的存儲空間從類類型的定義不難看出,類的數(shù)據(jù)成員(對象屬性)中保存的數(shù)據(jù)值代表了類對象的狀態(tài),決定了該類的不同對象的差別,因此當(dāng)類對象創(chuàng)建時,每個類對象都必須獨占一份(個數(shù)相同、類型相同)

數(shù)據(jù)成員存儲空間,用于保存區(qū)別于其他對象的狀態(tài);而類的成員函數(shù)描述了該類所有對象的統(tǒng)一行為操作,而操作結(jié)果(行為表現(xiàn))的差異取決于不同對象的狀態(tài),因此,成員函數(shù)的運(yùn)行代碼被存儲在與數(shù)據(jù)成員存儲空間不同的代碼空間中,被該類的所有對象共享。第30頁,共143頁,2023年,2月20日,星期四例如:由于語句Studentstud1,stud2,stud3;

執(zhí)行所創(chuàng)建的3

個Student

對象在程序運(yùn)行空間中占用內(nèi)存的大小和位置的狀態(tài)示意如下:返回程序數(shù)據(jù)區(qū)程序代碼區(qū)Student::Student()的運(yùn)行代碼Student::~Student()的運(yùn)行代碼Student::display()的運(yùn)行代碼numnamesexstud1numnamesexstud2numnamesexstud3第31頁,共143頁,2023年,2月20日,星期四3.3類對象的定義和使用3.3.1類與對象的關(guān)系⑴類是一組具有相同屬性和行為的對象的抽象,是創(chuàng)建對象的模板,是用戶使用class

創(chuàng)建的自定義類型。類一旦創(chuàng)建,其作用可與系統(tǒng)預(yù)定義類型(例如,int、double等)類比。⑵

對象是類的實例,創(chuàng)建類的對象可以與創(chuàng)建預(yù)定義類型的變量(例如,int

x;、doubled;等)類比。⑶類只是提供了該類對象的創(chuàng)建和使用的方法和規(guī)則,因此類本身不占用內(nèi)存。創(chuàng)建類對象時將按類定義提供的方法和規(guī)則,在內(nèi)存中為類對象分配空間,因此,封裝是對類對象而言的。第32頁,共143頁,2023年,2月20日,星期四3.3.2類對象的定義方法:1先創(chuàng)建類類型,使用時再定義對象

大多數(shù)情況均采用該方法定義類對象。這樣創(chuàng)建的類對象的生存周期取決于創(chuàng)建的位置。例如:

classStudent{…}; voidmain() {

StudentZhang,Li; //創(chuàng)建Student局部對象

… }

雖然C++

也允許將上述的類對象定義語句寫成:

classStudentZhang,Li;

(C

風(fēng)格)但不能體現(xiàn)C++

面向?qū)ο蟮脑O(shè)計風(fēng)格,且不方便簡潔,所以不提倡。第33頁,共143頁,2023年,2月20日,星期四2在創(chuàng)建類類型的同時定義對象。使用這種方法定義的類對象的生存周期取決于類類型的創(chuàng)建位置。例如: classStudent { intnum; charname[20]; charsex; public: voiddisplay(){ cout<<“num:”<<num<<endl; cout<<“name:”<<name<<endl; cout<<“sex:”<<sex<<endl; } }Zhang,Li;第34頁,共143頁,2023年,2月20日,星期四3不出現(xiàn)類名,直接定義對象。使用這種方法定義類對象的類類型一般在程序中只 出現(xiàn)和使用一次。例如,創(chuàng)建一個描述人員信息的 類類型person

中包含了一個聯(lián)系信息屬性成員

touchInfo,該屬性是一個由人員的通訊地址、郵政編 碼、電話號碼、e-mail等信息和相應(yīng)的處理操作構(gòu) 成的類類型對象,而該類類型只在定義touchInfo

屬 性出現(xiàn)和使用一次。此時就可以采用本方法在類類 型person

中定義touchInfo

屬性:第35頁,共143頁,2023年,2月20日,星期四 classperson

{ … class //無須類名 { stringAddess; stringpostCode; stringponeNum; stringE-mail; public: … }touchInfo; … };第36頁,共143頁,2023年,2月20日,星期四3.3.3類對象的使用

類的使用是通過首先創(chuàng)建類對象,然后引用類對象的公有成員(訪問數(shù)據(jù)成員或調(diào)用成員函數(shù))達(dá)到對該類的使用。依據(jù)類對象的創(chuàng)建方式不同,類的使用形式可以分為三種:1通過對象名和成員運(yùn)算符訪問對象成員 一般形式:對象名.成員名;

其中成員名必須是對象名所指明對象的所屬類的公 有數(shù)據(jù)成員名或公有成員函數(shù)名。例如:第37頁,共143頁,2023年,2月20日,星期四 classpoint{ intx,y; public: setpoint(intvx,intvy){x=vx;y=vy;} }; voidfun(){

pointpt; //創(chuàng)建point類對象pt

pt.setpoint(10,10); //給point對象pt的坐標(biāo)x,y賦值

pt.x=50;

//錯誤,不能訪問私有成員 ... }

代碼pt.setpoint(10,10)實際是pt.point::setpoint(10,10)

的縮寫,表明通過對象訪問對象名所指示的類成員。第38頁,共143頁,2023年,2月20日,星期四2通過指向?qū)ο蟮闹羔樤L問對象成員 一般形式:指針名->成員名; 其中成員名必須是指針?biāo)笇ο蟮乃鶎兕惖墓袛?shù) 據(jù)成員名或公有成員函數(shù)名。例如: classpoint{ intx,y; public: setpoint(intvx,intvy){x=vx;y=vy;} }; voidfun(){

point*p=newpoint; //p指向動態(tài)創(chuàng)建的point對象

p->setpoint(10,10);//給p所指對象的坐標(biāo)x,y賦值 ... }第39頁,共143頁,2023年,2月20日,星期四3通過對象的引用訪問對象成員 一般形式:對象引用名.成員名; 其中成員名必須是對象引用名所引用對象的所屬類

的公有數(shù)據(jù)成員名或公有成員函數(shù)名。例如: classpoint{ intx,y; public: setpoint(intvx,intvy){x=vx;y=vy;} }; voidfun(){

pointpt,&p=pt; //p引用point對象pt

p.setpoint(10,10); //給p引用的對象的坐標(biāo)x,y賦值 ... }第40頁,共143頁,2023年,2月20日,星期四3.3.4成員名解析

由于類成員作用域在該類定義體所限定的邊界內(nèi),因此,不同類中具有同名的成員是不會產(chǎn)生二義性。例如: classrealSet

//定義一個實數(shù)集合類 { … public: voidprint(); }; classintSet

//定義一個整數(shù)集合類 { … public: voidprint(); };第41頁,共143頁,2023年,2月20日,星期四 voidfun() {

intSet

is;

realSet

rs; …

is.print(); //調(diào)用intSet類中的print()函數(shù)

rs.print(); //調(diào)用realSet類中的print()函數(shù) } 顯然不會引起二義性錯誤。返回

第42頁,共143頁,2023年,2月20日,星期四3.4構(gòu)造函數(shù) 使用類定義對象時,需要一種操作,使所定義的對象與類的定義域相關(guān)。實現(xiàn)這一操作的成員函數(shù)稱為構(gòu)造函數(shù),該函數(shù)要完成的操作包括:⑴依據(jù)類數(shù)據(jù)成員的個數(shù)和類型為對象分配內(nèi)存;⑵根據(jù)需要為對象的數(shù)據(jù)成員進(jìn)行必要的初始化。 構(gòu)造函數(shù)是類必須擁有的特殊成員函數(shù),該函數(shù)從定義形式到使用場合和方法上都與一般成員函數(shù)有所區(qū)別,這些差異表現(xiàn)在以下幾個方面:第43頁,共143頁,2023年,2月20日,星期四⑴構(gòu)造函數(shù)名必須與類名相同,否則編譯器將會把它當(dāng)作一般成員函數(shù)對待。例如:

classStudent { public:

Student(); … };

Student::Student() { … }第44頁,共143頁,2023年,2月20日,星期四⑵構(gòu)造函數(shù)沒有返回值,因此,聲明和定義構(gòu)造函數(shù) 時都不能說明它的返回類型;⑶構(gòu)造函數(shù)的功能是將對象初始化,因此構(gòu)造函數(shù)一 般只對數(shù)據(jù)成員進(jìn)行初始化和必要的輔助操作,而 不提倡做與初始化無關(guān)的操作。⑷系統(tǒng)總會為類提供一個隱含的缺省構(gòu)造函數(shù)。該構(gòu) 造函數(shù)實際上是一個空定義體函數(shù),因此只能為對 象分配空間而不能為數(shù)據(jù)成員進(jìn)行初始化。 在大多數(shù)情況下,數(shù)據(jù)成員的初始化操作是十分必 要的,因此通常需要顯式定義構(gòu)造函數(shù)。構(gòu)造函數(shù) 一旦顯式定義,缺省構(gòu)造函數(shù)將被覆蓋。第45頁,共143頁,2023年,2月20日,星期四⑸在程序運(yùn)行過程中,類對象是在進(jìn)入其作用域時才 被創(chuàng)建的。也就是說,此時類對象的構(gòu)造函數(shù)被調(diào) 用。⑹構(gòu)造函數(shù)在類對象創(chuàng)建時由系統(tǒng)自動執(zhí)行,不需要 用戶調(diào)用,也不能由用戶調(diào)用。例如:

Studentstud1; //系統(tǒng)調(diào)用構(gòu)造函數(shù)創(chuàng)建stud1 stud1.Student(); //企圖用一般成員函數(shù)的調(diào)用方法

//調(diào)用構(gòu)造函數(shù),因此是錯誤的。⑺不能為構(gòu)造函數(shù)定義函數(shù)指針,也不能獲取構(gòu)造函 數(shù)的調(diào)用地址。⑻基類的構(gòu)造函數(shù)不能被派生類繼承。⑼構(gòu)造函數(shù)不能聲明為虛函數(shù)。第46頁,共143頁,2023年,2月20日,星期四例3-1

定義一個整數(shù)隊列類,使用由系統(tǒng)隱含提供的缺 省構(gòu)造函數(shù)創(chuàng)建整數(shù)隊列,并測試隊列功能。1問題分析

⑴用例分析

⑵類圖描述向隊列中裝入整數(shù)從隊列中取出整數(shù)用戶qurue-q[2..*]:int-head:int-tail:int+qput(ini:int)+qget():int第47頁,共143頁,2023年,2月20日,星期四

2詳細(xì)設(shè)計

⑴類設(shè)計①qurue類

ⅰ類定義 classqueue { intq[100]; //隊列空間 inthead,tail; //隊列頭、尾指示 public: voidqput(inti); //隊列插入操作 intqget(); //隊列取出操作 };第48頁,共143頁,2023年,2月20日,星期四

ⅱ算法描述 成員函數(shù)qput

的N-S

流程圖: 成員函數(shù)qget

的N-S

流程圖:

tail==100&&tail-head==100?

真假顯示"隊列滿"

trail=trail+1,數(shù)據(jù)插入隊尾

head==tail?真假顯示"隊列空"

head=head+1

從隊頭取數(shù)據(jù)

tail==100?真 假移動隊列數(shù)據(jù),修改隊列指針tail=tail–head;head=0;第49頁,共143頁,2023年,2月20日,星期四

⑵類對象創(chuàng)建和使用

main函數(shù)的N-S流程圖:使用queue類創(chuàng)建實例a,b向隊列實例a,b中分別插入:10,20和20,19從隊列實例a,b中分別順序取出數(shù)據(jù),并顯示第50頁,共143頁,2023年,2月20日,星期四3.4.1參數(shù)化的構(gòu)造函數(shù)

與其他成員函數(shù)一樣,構(gòu)造函數(shù)也可以有參數(shù)。通過這些參數(shù)為類對象的數(shù)據(jù)成員傳遞初值。例如: classpoint { intx,y; public:

point(intvx,intvy); //聲明帶參數(shù)的構(gòu)造函數(shù) voidoffset(intax,intay); };第51頁,共143頁,2023年,2月20日,星期四

point::point(intvx,intvy) { x=vx; //用傳遞來的實參對x,y賦初值

y=vy; } main() {

pointp(10,20); //定義對象,并傳遞初值

//… }注意,不要將使用參數(shù)創(chuàng)建類對象的代碼寫成:

pointp=point(10,20);第52頁,共143頁,2023年,2月20日,星期四3.4.2構(gòu)造函數(shù)的重載 在一個類中允許定義多個參數(shù)不同構(gòu)造函數(shù),即構(gòu)造函數(shù)重載。這樣就為在不同情況下創(chuàng)建對象的特定初始化需要提供了實現(xiàn)手段。也就是說,在類對象定義時,編譯器可以依據(jù)創(chuàng)建對象所需要的參數(shù)差異確定調(diào)用構(gòu)造函數(shù)的哪一個版本來創(chuàng)建類對象。例3-1-1

定義一個有兩個構(gòu)造函數(shù)的類,并使用不同構(gòu) 造函數(shù)定義對象。第53頁,共143頁,2023年,2月20日,星期四3.4.3使用缺省參數(shù)值的構(gòu)造函數(shù)與其他函數(shù)一樣,構(gòu)造函數(shù)的參數(shù)也可以具有缺省值,表示類對象的某些屬性在大多數(shù)情況下是預(yù)先可以確定的缺省狀態(tài),例如計數(shù)器的初值一般為“0”、戰(zhàn)士的性別多數(shù)為“男”、大學(xué)教師的學(xué)位一般為“碩士”等。構(gòu)造函數(shù)的缺省參數(shù)值的定義和使用規(guī)則與其他帶缺省參數(shù)值的函數(shù)相同。例3-1-2

描述了如何聲明,定義和使用帶有缺省參數(shù)值 的類構(gòu)造函數(shù)。第54頁,共143頁,2023年,2月20日,星期四歸納構(gòu)造函數(shù)使用缺省參數(shù)值的編程要點是:⑴指定缺省參數(shù)值只能在構(gòu)造函數(shù)的聲明中,而不能 出現(xiàn)在構(gòu)造函數(shù)定義的首部。構(gòu)造函數(shù)定義在類定 義體中的情況除外。⑵函數(shù)聲明中的參數(shù)可以省略參數(shù)名,此時指定缺省參數(shù)值的格式為:類型名=缺省值。例如:

Box(int=10,int=10,int=10);⑶如果構(gòu)造函數(shù)的全部參數(shù)都指定了缺省值,應(yīng)該避 免再定義一個無參數(shù)的構(gòu)造函數(shù)。因為在定義構(gòu)造函數(shù)時,編譯器會認(rèn)為可能是重復(fù)定義。例如:

Box();

Box(int=10,int=10,int=10);第55頁,共143頁,2023年,2月20日,星期四 更重要的是定義類對象時,遇到如下情況:

Boxbox1;

編譯器無法確定調(diào)用哪一個構(gòu)造函數(shù)版本來創(chuàng)建類 對象。⑷如果構(gòu)造函數(shù)的全部參數(shù)都指定了缺省值,就容易 在重載構(gòu)造函數(shù)時造成二義性。例如:

Box(int=10,int=10,int=10);

Box();

Box(int,int);

因此,應(yīng)避免全部參數(shù)都指定了缺省值。例如:

Box();

Box(int,int=10,int=10);

Box(int,int);第56頁,共143頁,2023年,2月20日,星期四3.4.4用參數(shù)初始化表對數(shù)據(jù)成員初始化所謂參數(shù)初始化是指系統(tǒng)在為類對象的各個數(shù)據(jù)成員分配內(nèi)存空間的同時能按照用戶通過參數(shù)指定的值為數(shù)據(jù)成員賦值,而不是在各個數(shù)據(jù)成員的內(nèi)存空間分配完成后,再對它們進(jìn)行賦值。這就需要通過一種語法格式,即參數(shù)初始化表,使編譯器能按照上述要求實現(xiàn)對類對象的各個數(shù)據(jù)成員的初始化。構(gòu)造函數(shù)參數(shù)初始化表的一般形式為:

:[基類初始化列表],[屬性初始化列表]第57頁,共143頁,2023年,2月20日,星期四其中基類初始化列表只有在派生類的構(gòu)造函數(shù)初始化表才會存在,這一部分將在第五章中介紹。屬性初始化列表由若干個屬性初始化項組成,項間用“,”隔開:

屬性初始化項1,

屬性初始化項2,…

屬性初始化項n每個屬性初始化項的一般格式為:

屬性名(參數(shù)列表)不難看出,屬性初始化項的含義是調(diào)用相應(yīng)的屬性類的具有參數(shù)的構(gòu)造函數(shù)用于屬性對象的創(chuàng)建和賦初值操作。第58頁,共143頁,2023年,2月20日,星期四 這從另一個角度告訴我們,一個構(gòu)造函數(shù)的定義中沒有出現(xiàn)初始化表意味著使用了隱含的初始化表,該表的功能是分別調(diào)用了相應(yīng)類的無參數(shù)(或有缺省參數(shù)值)構(gòu)造函數(shù)完成類對象的基類部分和各個屬性對象創(chuàng)建和賦初值。例3-1-3

是將例3-1-1中的類構(gòu)造函數(shù)改寫為使用參數(shù)初 始化表實現(xiàn)類對象各數(shù)據(jù)成員的初始化。 雖然兩個實例中對類對象的數(shù)據(jù)成員初始化的結(jié)果是完全相同的,但兩種初始化方法對數(shù)據(jù)成員的賦值的時間和方法是完全不同的。第59頁,共143頁,2023年,2月20日,星期四 在構(gòu)造函數(shù)定義中使用初始化表另一個非常重要的原因就是對于類對象的常數(shù)據(jù)成員、引用數(shù)據(jù)成員的初始化就必須在創(chuàng)建的同時進(jìn)行賦值操作,而不能在函數(shù)體中進(jìn)行賦值。例如:

classA{ public:

A(inti);

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

private:

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

};

A::A(inti):a(i),ref(a){}第60頁,共143頁,2023年,2月20日,星期四3.4.5拷貝構(gòu)造函數(shù)

拷貝構(gòu)造函數(shù)是一個特定的構(gòu)造函數(shù)。該構(gòu)造函數(shù)與其他構(gòu)造函數(shù)在形式上的差別僅在于函數(shù)的參數(shù)必須是同類型對象的常引用。拷貝構(gòu)造函數(shù)的原型格式如下:

類型名(const

類型名&

引用名);

拷貝構(gòu)造函數(shù)的功能是創(chuàng)建一個新對象,并將參數(shù)所引用對象的各個數(shù)據(jù)成員值復(fù)制到新對象的對應(yīng)的數(shù)據(jù)成員域中。第61頁,共143頁,2023年,2月20日,星期四系統(tǒng)會為每個類缺省定義一個拷貝構(gòu)造函數(shù),也允許用戶定義一個拷貝構(gòu)造函數(shù),用以取代缺省的拷貝構(gòu)造函數(shù)。一般情況下,使用系統(tǒng)定義的缺省拷貝構(gòu)造函數(shù)就可以滿足類對象的復(fù)制操作,但在有些情況下,用戶必須定義自己的拷貝構(gòu)造函數(shù)。例如:

classstring

{ intlength; char*str; //指針數(shù)據(jù)成員

public:

string(intlen); … };第62頁,共143頁,2023年,2月20日,星期四 string::string(intlen) { length=len;

str=newchar[len+1];

//指針數(shù)據(jù)成員指向動態(tài)分配的內(nèi)存空間

} main() { strings1(10); //創(chuàng)建一個string對象s1 strings2(s1); //復(fù)制s1到新string對象s2 … }第63頁,共143頁,2023年,2月20日,星期四在這種情況下,s1

和s2

的指針數(shù)據(jù)成員str

指向了同一內(nèi)存空間,使得通過str對該內(nèi)存空間的任何操作都不能保持應(yīng)有的獨立性。更嚴(yán)重的是當(dāng)s1和s2

之中有一個被撤消時,在堆中分配的內(nèi)存空間被撤消回收,使得另一個string

對象的指針數(shù)據(jù)成員str

成為無效指針,任何通過該指針的操作均為非法操作,會導(dǎo)致嚴(yán)重的運(yùn)行錯誤。造成這一問題的原因是系統(tǒng)提供的缺省拷貝構(gòu)造函數(shù)不能復(fù)制string對象。因此,在這種情況下必須定義自己的拷貝構(gòu)造函數(shù):lengthstrs1lengthstrs2第64頁,共143頁,2023年,2月20日,星期四

string::string(conststring&s) { length=s.length; str=

newchar[length+1]; strcpy(str,s.str); }

Java

沒有C++

那種含義的指針,也沒有拷貝構(gòu)造函數(shù)。同時,對象的撤消是由垃圾收集器完成的,因此也不會產(chǎn)生像C++

中那樣的問題。當(dāng)然在Java

中也可以用賦值運(yùn)算符“=”來進(jìn)行對象賦值,但是,這并不意味著一個簡單賦值操作所具有的直覺含義。例如:第65頁,共143頁,2023年,2月20日,星期四

classUser { publicstringname; … } classTest { publicstaticvoidmain(String[]args){

Useru1=newUser(“ariel”,112); System.out.println();

//ariel

Useru2=u1; =“muriel”; System.out.println();

//muriel } }第66頁,共143頁,2023年,2月20日,星期四顯然,這里的u2=u1

只是對對象引用的復(fù)制。由于u1

和u2

引用同一個User

對象,所以才會導(dǎo)致修改

實際上等價于對

的修改(這與C++

中兩個指針指向同一個對象的情況類似)。如果要完成直覺意義上的復(fù)制,就必須通過實現(xiàn)User

類的克隆接口Cloneable后,調(diào)用逐字節(jié)復(fù)制的克隆函數(shù)

clone()

完成。例如:第67頁,共143頁,2023年,2月20日,星期四

classUserimplementsCloneable

{ publicstringname; … } classTest { publicstaticvoidmain(String[]args){

Useru1=newUser(“ariel”,112); System.out.println();

//ariel

Useru2=(User)u1.clone(); =“muriel”;

System.out.println();

//ariel

} }第68頁,共143頁,2023年,2月20日,星期四3.5析構(gòu)函數(shù)

對象撤消時,也需要一種操作,使被撤消的對象從程序的數(shù)據(jù)區(qū)中合法消失。實現(xiàn)這一操作的成員函數(shù)稱為析構(gòu)函數(shù),該函數(shù)要完成的操作包括:⑴回收被撤消對象數(shù)據(jù)成員所占用的內(nèi)存;⑵根據(jù)需要完成回收被撤消對象數(shù)據(jù)成員所占內(nèi)存之 前的必要操作。 析構(gòu)函數(shù)也是類必須擁有的特殊成員函數(shù),該函數(shù)從定義形式到使用場合和方法上都與構(gòu)造函數(shù)相似,主要特點表現(xiàn)在以下幾個方面:第69頁,共143頁,2023年,2月20日,星期四⑴析構(gòu)函數(shù)名必須是類名加字符“~”前綴,否則編譯器將會把它當(dāng)作一般成員函數(shù)對待。例如:

classStudent { public:

~Student(); … };

Student::~Student() { … }第70頁,共143頁,2023年,2月20日,星期四⑵析構(gòu)函數(shù)沒有返回值,因此,聲明和定義析構(gòu)函數(shù) 時都不能說明它的返回類型;⑶系統(tǒng)總會為類提供一個隱含的缺省析構(gòu)函數(shù)。該析 構(gòu)函數(shù)實際上是一個空定義體函數(shù),因此只能撤消 回收對象所占用的空間。 如果在對象被撤消之前無須做必要的預(yù)處理操作, 則可以放心使用缺省析構(gòu)函數(shù)。但在有些情況下, 則必須定義自己析構(gòu)函數(shù)。析構(gòu)函數(shù)一旦顯式定義,缺省析構(gòu)函數(shù)將被覆蓋。例如:第71頁,共143頁,2023年,2月20日,星期四classstring

{ intlength;

char*contents;public: string(char*s); //聲明構(gòu)造函數(shù) ~string(); //聲明析構(gòu)函數(shù)};類string的對象在撤消之前需要先檢查指針類型屬性contents

是否指向有效的內(nèi)存空間,如果是,則應(yīng)回收所占用的內(nèi)存空間。因此,必須重新定義析構(gòu)函數(shù),取代系統(tǒng)隱含定義的缺省析構(gòu)函數(shù)。string類的構(gòu)造函數(shù)和析構(gòu)函數(shù)的操作可以按如下定義:第72頁,共143頁,2023年,2月20日,星期四

string::string(char*s) //定義構(gòu)造函數(shù)

{ if(s) {length=strlen(s);

contents=newchar[length+1]; //分配存儲

strcpy(contents,s); //字串賦值

} else {length=0;

contents=0; //設(shè)置指針數(shù)據(jù)成員為空

}}第73頁,共143頁,2023年,2月20日,星期四

string::~string() //定義析構(gòu)函數(shù)

{ if(contents)delete[]contents; //釋放contents指向的內(nèi)存空間

}⑷在程序運(yùn)行過程中,類對象是在退出其作用域時才 被析構(gòu)的。也就是說,此時類對象的析構(gòu)函數(shù)被調(diào) 用。⑸析構(gòu)函數(shù)在類對象撤消時由系統(tǒng)自動執(zhí)行,不需要 用戶調(diào)用,也不能由用戶直接調(diào)用。第74頁,共143頁,2023年,2月20日,星期四⑹不能為析構(gòu)函數(shù)定義函數(shù)指針,也不能獲取析構(gòu)函 數(shù)的調(diào)用地址。⑺基類的析構(gòu)函數(shù)不能被派生類繼承。⑻析構(gòu)函數(shù)可以聲明為虛函數(shù),并且提倡聲明為虛函 數(shù)(詳細(xì)原因在第六章運(yùn)行多態(tài)性中講述)。返回第75頁,共143頁,2023年,2月20日,星期四3.6對象的動態(tài)創(chuàng)建和釋放與預(yù)定義類型一樣,自定義類型也可以使用運(yùn)算符new

動態(tài)創(chuàng)建對象和使用運(yùn)算符delete

撤消類對象。例3-2

描述了動態(tài)創(chuàng)建、撤消和使用point

類對象。注意:1使用無參數(shù)或具有缺省參數(shù)值的構(gòu)造函數(shù)動態(tài)創(chuàng)建 類對象(即創(chuàng)建對象時不傳遞初始值)的格式為:

new

類型名;

例如,point*p=newpoint;

而不應(yīng)寫成:

new

類型名();

例如,point*p=newpoint();

上述格式與動態(tài)創(chuàng)建系統(tǒng)預(yù)定義類型變量的格式完 全一致(預(yù)定義類型無缺省初始值)。例如:

int*p=newint;第76頁,共143頁,2023年,2月20日,星期四2使用有參數(shù)的構(gòu)造函數(shù)動態(tài)創(chuàng)建類對象(即創(chuàng)建對 象時傳遞初始值)的格式為:

new

類型名(初始值…);

例如,point*p=newpoint(10,20);

上述格式與動態(tài)創(chuàng)建系統(tǒng)預(yù)定義類型變量并傳遞初 始值的格式完全一致。例如:

int*p=newint(10);第77頁,共143頁,2023年,2月20日,星期四例3-3

通過構(gòu)造函數(shù)對對象數(shù)組進(jìn)行初始化。對象數(shù)組初始化的方法一般有兩種:1使用缺省構(gòu)造函數(shù)創(chuàng)建對象數(shù)組后,調(diào)用一個專門 用于初始化的成員函數(shù)對數(shù)組中的每個對象分別進(jìn) 行初始化。該方法雖然必須分兩步完成對象數(shù)組的 創(chuàng)建和初始化,但可以將對象數(shù)組中的元素初始化 為任意值。2定義一個帶缺省值參數(shù)的構(gòu)造函數(shù)。使得在創(chuàng)建對 象數(shù)組的同時,由構(gòu)造函數(shù)的缺省參數(shù)值完成數(shù)組 中的每個對象對象的初始化。使用該方法創(chuàng)建和初 始化對象數(shù)組簡單、方便,但只能將對象數(shù)組中的 每個元素初始化為固定的缺省值。 返回第78頁,共143頁,2023年,2月20日,星期四3.7對象的賦值與復(fù)制1對象的賦值 對象的賦值只能發(fā)生在同類型對象之間的,這與系統(tǒng)預(yù)定義類型變量的賦值是一致的。對象賦值的一般格式為:

對象名1

=

對象名2;

賦值操作是由賦值運(yùn)算符“=”完成的,該運(yùn)算符(函 數(shù))的功能是將對象名2

所指示對象的各個數(shù)據(jù)成員 值依次傳遞給對象名1

所指示對象的各個數(shù)據(jù)成員, 使對象1

與對象2

完全相同。第79頁,共143頁,2023年,2月20日,星期四 系統(tǒng)會為每一個自定義類型自動添加一個隱含的缺 省賦值運(yùn)算符,因此一般的自定義類型不必顯式定 義賦值運(yùn)算符。但如果類定義中包含有指針類屬性 (3.4.5

拷貝構(gòu)造函數(shù)中已經(jīng)討論這種情況),則必 須顯式定義賦值運(yùn)算符用于取代隱含的缺省賦值運(yùn) 算符。如何定義賦值運(yùn)算符將在第五章中討論。

例3-2-1

描述了使用缺省賦值運(yùn)算符完成對象的賦值 操作。第80頁,共143頁,2023年,2月20日,星期四2對象的復(fù)制 對象的復(fù)制是指按照一個已經(jīng)存在的對象創(chuàng)建一個與該對象完全相同的新對象。顯然對象的復(fù)制操作是由類的拷貝構(gòu)造函數(shù)完成的,復(fù)制一個已有對象的一般形式為:

類型名

對象2(對象1);

例如,Boxbox2(box1);

在C++中上述復(fù)制也適用于預(yù)定義類型,即每個預(yù) 定義類型都有一個隱含的拷貝構(gòu)造函數(shù)。 例如,int

a(10),b(a);第81頁,共143頁,2023年,2月20日,星期四

C++

還提供了另外一種方便用戶的復(fù)制表達(dá)式,即用賦值運(yùn)算符代替括號調(diào)用類的拷貝構(gòu)造函數(shù):

類型名

對象2=對象1;

例如,Box

box2=box1;

顯然,這種復(fù)制形式與預(yù)定義類型變量賦值定義形式是一致的。 例如,inta=10,b=a;

程序中需要對象復(fù)制操作的情況有三種: ⑴用戶需要定義與已有對象完全一致的新對象。 ⑵函數(shù)調(diào)用時,系統(tǒng)需要復(fù)制被傳遞的實參對象。 ⑶函數(shù)返回時,系統(tǒng)會復(fù)制被返回的操作結(jié)果。返回第82頁,共143頁,2023年,2月20日,星期四3.8與對象有關(guān)的指針 指針變量可以用于指向任何預(yù)定義類型變量,當(dāng)然也可以指向自定義類型對象。不僅如此,指針變量還可以指向?qū)ο蟮念惓蓡T。1指向?qū)ο蟮闹羔?定義指向?qū)ο蟮闹羔樧兞康囊话阈问剑?/p>

類型名

*對象指針名; 例如,Box*pt;

顯然,這與定義預(yù)定義類型指針的形式是完全一致的。同樣,指針的使用形式也是相同的。例如:

pt=newBox;

pt->volume(); //與(*pt).volume();等價第83頁,共143頁,2023年,2月20日,星期四2指向?qū)ο蟪蓡T的指針 對象的成員有數(shù)據(jù)成員和成員函數(shù)兩種,因此指向 對象成員的指針也有兩種。 ⑴指向數(shù)據(jù)成員的指針 定義指向數(shù)據(jù)成員的指針變量的一般形式:

類型名

*指針變量名;

顯然,這與定義預(yù)定義類型指針是完全一致的。 同樣,指針的使用形式也是相同的。例如:

classTime{ public: inthour,minute,sec; voidshow(); };第84頁,共143頁,2023年,2月20日,星期四

voidTime::show() { cout<<hour<<“:”<<minute<<“:”<<sec<<endl; }

Timetime;

int*p;

p=&time.hour;

而不能按如下表達(dá)式為指針賦值:

p=&Time::hour;

注意,指針只能指向公有數(shù)據(jù)成員。第85頁,共143頁,2023年,2月20日,星期四 ⑵指向?qū)ο蟪蓡T函數(shù)的指針 定義指向成員函數(shù)的指針變量的一般表達(dá)式:

類型名

(類名::*函數(shù)指針名)(參數(shù)列表);

例如,void(Time::*pf)();

為函數(shù)指針賦值,指向成員函數(shù)的一般表達(dá)式:

函數(shù)指針名

=&類名::成員函數(shù)名;

例如,pf=&Time::Show;

通過成員函數(shù)指針調(diào)用成員函數(shù)的一般表達(dá)式:

(對象名.*成員函數(shù)指針)(實參列表);

例如,Timetime; (time.*pf)();

或者(對象指針->*成員函數(shù)指針)(實參列表);

例如,Time*pt=&time; (pt->*pf)();第86頁,共143頁,2023年,2月20日,星期四3this

指針

this指針是類成員函數(shù)擁有的一個隱含指針,它指向該成員函數(shù)被調(diào)用時,操作所施加的類對象地址,實現(xiàn)不同對象的相同行為的表現(xiàn)差異。如圖所示:成員函數(shù){………}this數(shù)據(jù)成員…類對象1數(shù)據(jù)成員…類對象2數(shù)據(jù)成員…類對象n第87頁,共143頁,2023年,2月20日,星期四 成員函數(shù)通過this

指針可以訪問所指對象中的類成 員,數(shù)據(jù)成員的訪問格式可寫為:

this->數(shù)據(jù)成員名 成員函數(shù)的訪問格式可寫成:

this->成員函數(shù)名(參數(shù)列表)

例如:第88頁,共143頁,2023年,2月20日,星期四

classexth{ inti; public: voidload(intval) {this->i=val;} //與i=val;等價

intget() {returnthis->i;} //與returni;等價

}; voidmain() {

exthobj; obj.load(100); cout<<obj.get(); }第89頁,共143頁,2023年,2月20日,星期四 顯然,一般情況下,上述書寫格式是繁瑣的,并且 是不必要的。但在成員函數(shù)的形參名與某個數(shù)據(jù)成 員名相同時,使用this

指針是區(qū)分這兩個數(shù)據(jù)變量 的好方法。例如:

point::point(intx,inty) {

this->x=x; this->y=y; }

當(dāng)然,這種問題也可以用如下方法解決:

point::point(intx,inty) {

point::x=x; point::y=y; }第90頁,共143頁,2023年,2月20日,星期四

為了進(jìn)一步了解成員函數(shù)被調(diào)用時this

指針是如何在“幕后”工作的,我們再來分析一段程序:

classabc{private: chara; intb;public: voidinit(charma,intmb){a=ma;b=mb;}};intmain(){

abcob; ob.init(‘x’,12);

return0;}第91頁,共143頁,2023年,2月20日,星期四分析:在main()

中,abc

類成員函數(shù)init通過類對象

ob

被調(diào)用的:

ob.init(‘x’,12);

C++

是如何使this

指針指向?qū)ο髈b

的呢?編譯器在編譯過程中對上述語句經(jīng)過如下的轉(zhuǎn)換:①

首先將成員運(yùn)算符“.”之前的對象ob

的地址作為 實參傳給函數(shù)init,則語句變?yōu)椋?/p>

init(&ob,‘x’,12);

第92頁,共143頁,2023年,2月20日,星期四 ②

雖然成員函數(shù)init

的原型中沒有相應(yīng)的形參,但 程序編譯時,編譯器將該函數(shù)的原型和定義隱含 轉(zhuǎn)換成以下形式:

init(abc*this,charma,intmb)

{this->a=ma;this->b=mb;}

顯然,該成員函數(shù)被調(diào)用時,第一個形參應(yīng)是調(diào) 用該成員函數(shù)的對象地址,因此當(dāng)對象

ob

調(diào)用 成員函數(shù)init

時,形參this

=

&ob。確保成員函數(shù)

init

的操作施加于對象ob。 返回第93頁,共143頁,2023年,2月20日,星期四3.9靜態(tài)成員 前面我們所涉及到的類成員都是由每個對象獨享,即每個對象擁有獨立的數(shù)據(jù)成員空間,成員函數(shù)的調(diào)用都依賴某個特定對象,成員函數(shù)的操作結(jié)果取決于該對象的狀態(tài),并僅服務(wù)于該對象。這些由對象獨享的成員被稱為非靜態(tài)成員,是類的主要組成成員。此外,類中還需要包括一些由類的所有對象共享的成員,即類的所有對象共同擁有的數(shù)據(jù)成員和調(diào)用不依賴于某個特定對象,操作結(jié)果為類的所有對象服務(wù)的成員函數(shù)。這些由類的所有對象共享的成員被稱為靜態(tài)成員。在類中聲明靜態(tài)成員的方法就是用關(guān)鍵字

static聲明數(shù)據(jù)成員和成員函數(shù);第94頁,共143頁,2023年,2月20日,星期四3.9.1靜態(tài)數(shù)據(jù)成員 與非靜態(tài)數(shù)據(jù)成員不同,靜態(tài)數(shù)據(jù)成員屬于類的所有對象,因此無論創(chuàng)建多少個該類的對象,靜態(tài)數(shù)據(jù)成員在內(nèi)存中都只有一個。也就是說,靜態(tài)數(shù)據(jù)成員所占的內(nèi)存空間不在任何一個類對象空間中,因此類的構(gòu)造函數(shù)不會為靜態(tài)數(shù)據(jù)成員分配空間的初始化。第95頁,共143頁,2023年,2月20日,星期四例3-4

中Student

類中的數(shù)據(jù)成員count

用于存放學(xué)生總 數(shù)。顯然,不管有多少學(xué)生,學(xué)生總數(shù)只有一 個。也就是說,學(xué)生總數(shù)

count

屬于

Student

類的 所有對象,因此應(yīng)聲明為靜態(tài)數(shù)據(jù)成員。而數(shù)據(jù) 成員StudentNo

用于存放每個學(xué)生的學(xué)號,因此 該數(shù)據(jù)成員必須是非靜態(tài)數(shù)據(jù)成員。下圖描述了 這兩種數(shù)據(jù)成員與Student

類對象的關(guān)系:Student1:StudentNoStudent2:StudentNoStudent4:StudentNocount第96頁,共143頁,2023年,2月20日,星期四使用靜態(tài)數(shù)據(jù)成員的四點說明:⑴靜態(tài)數(shù)據(jù)成員屬于類的所有對象,而不像非靜態(tài)數(shù)據(jù)成員那樣屬于某一個對象,是整個類的屬性。因此訪問靜態(tài)數(shù)據(jù)成員的形式通常采用:

類名::數(shù)據(jù)成員名。

例如,Student::count

C++

編譯器也允許采用通過對象名訪問靜態(tài)數(shù)據(jù)成員的形式:

對象名.數(shù)據(jù)成員名。

例如,Student1.count

后一種形式等價與Student1.Student::count,顯然對象名是多余的。第97頁,共143頁,2023年,2月20日,星期四⑵類中聲明的靜態(tài)數(shù)據(jù)成員既不能隨著對象創(chuàng)建被定義和初始化,也不能在類定義中進(jìn)行定義和初始化,而必須在類定義外,并且在該類的任何對象創(chuàng)建之前,提供初始化定義。一般形式為:

數(shù)據(jù)類型

類名::靜態(tài)數(shù)據(jù)成員名

=初值;

例如本例中為Student::count

提供初始化定義語句:

intStudent::count=0;

如果只定義不賦初值,則被缺省設(shè)置為零。注意,對于類的常靜態(tài)(staticconst)數(shù)據(jù)成員,也需要和一般靜態(tài)數(shù)據(jù)成員一樣在類外初始化。第98頁,共143頁,2023年,2月20日,星期四⑶靜態(tài)數(shù)據(jù)成員與其他靜態(tài)變量一樣,是在編譯時創(chuàng)建并被初始化的。它在該類的任何對象被

溫馨提示

  • 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

提交評論