面向?qū)ο蟪绦蛟O(shè)計之類和對象2_第1頁
面向?qū)ο蟪绦蛟O(shè)計之類和對象2_第2頁
面向?qū)ο蟪绦蛟O(shè)計之類和對象2_第3頁
面向?qū)ο蟪绦蛟O(shè)計之類和對象2_第4頁
面向?qū)ο蟪绦蛟O(shè)計之類和對象2_第5頁
已閱讀5頁,還剩76頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

Object-Oriented

Programming

inC++

第三章再論類和對象3.1構(gòu)造函數(shù)3.2析構(gòu)函數(shù)3.3調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)的順序3.4對象數(shù)組3.5對象指針3.6共用數(shù)據(jù)的保護3.7對象的動態(tài)建立和釋放3.8對象的賦值和復(fù)制3.9靜態(tài)成員3.10友元3.11類模板3.1構(gòu)造函數(shù)對象的初始化 和普通變量一樣,我們定義一個變量,往往同時進行初始化:

inta=3;

而聲明類時,數(shù)據(jù)成員進行初始化:

classtime {inthour=0;

intminute=0;

intsecond=0; }

?3.1構(gòu)造函數(shù) 定義對象時(而不是聲明類時)進行初始化:

classtime {public/private:

inthour;

intminute;

intsecond; }; timet1={13,30,20};

3.1構(gòu)造函數(shù)構(gòu)造函數(shù)的作用

C++提供了構(gòu)造函數(shù)(constructor)來處理對象的初始化。構(gòu)造函數(shù)是一個由用戶定義的特殊的成員函數(shù)。與其他成員函數(shù)不同之處在于:用戶不能調(diào)用它,而是在定義對象時,有系統(tǒng)自動調(diào)用構(gòu)造函數(shù)。構(gòu)造函數(shù)的名字必須與類名一致,不能是其他名字。構(gòu)造函數(shù)不能有任何返回類型。用戶如果沒有定義構(gòu)造函數(shù),系統(tǒng)會自動生成一個構(gòu)造函數(shù),只不過函數(shù)體中沒有任何語句。3.1構(gòu)造函數(shù)例將前例的時間類定義構(gòu)造函數(shù)。在構(gòu)造函數(shù)中加入輸出語句,看看運行效果。classtime{private:

inthour,minute,second;public:

time()//time類的構(gòu)造函數(shù)

{hour=0;minute=0;second=0;}voidsetTime();voidshowTime(){cout<<hour<<“:”<<minute<<“:”<<second<<endl;}};voidtime::setTime(){cout<<“hour=“<<endl;cin>>hour;

cout<<“minute=“<<endl;in>>minute;

cout<<“second=“<<endl;cin>>second;}voidmain(){timet1;//定義time類對象t1,調(diào)用構(gòu)造函數(shù)tume()t1.setTime();t1.showTime();timet2;//定義time類對象t2,調(diào)用構(gòu)造函數(shù)tume()t2.setTime();t2.showTime();}3.1構(gòu)造函數(shù)類外定義構(gòu)造函數(shù)classTime{public:Time();voidshow_time();private:

inthour;

intminute;

intsec;};

Time::Time(){hour=0;minute=0;sec=0;}

voidt1.time()Cout<<“構(gòu)造函數(shù)”;3.1構(gòu)造函數(shù)帶參數(shù)的構(gòu)造函數(shù)

聲明一個構(gòu)造函數(shù)的一般格式為: 構(gòu)造函數(shù)名(類型1形參1,類型2形參2,…);定義一個對象的一般格式為: 類名對象名(實參1,實參2,…);3.1構(gòu)造函數(shù)例3.2:有兩個長方體,長寬高分別為(1,2,3)和(4,5,6)。試編寫一基于對象的程序,分別求他們的體積,并且要求用帶參數(shù)的構(gòu)造函數(shù)初始化他們。#include<iostream.h>classbox{private:

intheight,width,length;public:

box(inth,intw,int

len){height=h;width=w;length=len;}

intvolume(){returnheight*width*length;}};voidmain(){boxbox1(1,2,3);

cout<<“box1的體積為”<<box1.volume()<<endl;boxbox2(4,5,6);

cout<<“box2的體積為”<<box2.volume()<<endl;}改寫為類外定義該構(gòu)造函數(shù)P723.1構(gòu)造函數(shù)用參數(shù)初始化表對數(shù)據(jù)成員初始化 這種方法不在函數(shù)體內(nèi)初始化數(shù)據(jù)成員,而是在函數(shù)首部實現(xiàn)。#include<iostream.h>classbox{private:

intheight,width,length;public:

box(int

h,int

w,int

len):height(h),width(w),length(len){}

intvolume(){returnheight*width*length;}};voidmain(){boxbox1(1,2,3);

cout<<“box1的體積為”<<box1.volume()<<endl;boxbox2(4,5,6);

cout<<“box2的體積為”<<box2.volume()<<endl;}3.1構(gòu)造函數(shù) 示例中的初始化表表示,用形參h的值初始化數(shù)據(jù)成員height,用w值初始化width,用len值初始化length。這種初始化方法比較簡練,可以直接在類體中定義構(gòu)造函數(shù)。box(inth,intw,intlen):height(h),width(w),length(len){}3.1構(gòu)造函數(shù)構(gòu)造函數(shù)的重載 一個類中,可以有多個構(gòu)造函數(shù),只要他們的參數(shù)表不同。以方便同類對象不同初始化的需要。見下例

:#include<iostream>usingnamespacestd;classBox{public:Box();

Box(int

h,intw,int

len):height(h),width(w),length(len){}

intvolume();private:

intheight;

intwidth;

intlength;};Box::Box(){height=10;width=10;length=10;}int

Box::volume(){return(height*width*length);}

intmain(){Boxbox1;

cout<<"Thevolumeofbox1is"<<box1.volume()<<endl;Boxbox2(15,30,25);

cout<<"Thevolumeofbox2is"<<box2.volume()<<endl;return0;}構(gòu)造函數(shù)的重載

#include<iostream.h>classcircle{private:floatradius;public://聲明一個無參數(shù)構(gòu)造函數(shù)//聲明一個帶參數(shù)構(gòu)造函數(shù)floatarea(){returnradius*radius*3.14159;}};voidmain(){circlec1(1.0),c2;

cout<<“c1的面積為”<<c1.area()<<endl;

cout<<“c2的面積為”<<c2.area()<<endl;}3.1構(gòu)造函數(shù)構(gòu)造函數(shù)的重載

#include<iostream.h>classcircle{private:floatradius;public:

circle();

//聲明一個無參數(shù)構(gòu)造函數(shù)circle(floatr):radius(r){}//聲明一個帶參數(shù)構(gòu)造函數(shù)floatarea(){returnradius*radius*3.14159;}};circle::circle(){radius=10.0;}voidmain(){circlec1(1.0),c2;

cout<<“c1的面積為”<<c1.area()<<endl;

cout<<“c2的面積為”<<c2.area()<<endl;}3.1構(gòu)造函數(shù)說明參數(shù)表為空的構(gòu)造函數(shù)叫默認(rèn)構(gòu)造函數(shù),一個類中只能有一個默認(rèn)函數(shù)。

定義對象時,如果想用默認(rèn)構(gòu)造函數(shù)初始化它,正確的定義形式為:

circlec2;

而不是:

circlec2();

一個類盡管定義了多個構(gòu)造函數(shù),一個對象只能用其中一個來初始化。

3.1構(gòu)造函數(shù)使用默認(rèn)參數(shù)的構(gòu)造函數(shù) 構(gòu)造函數(shù)的參數(shù)既可以通過實參傳送,也可以指定為某些默認(rèn)值。當(dāng)用戶不指定實參值時,編譯系統(tǒng)便將默認(rèn)值為形參值。 采用默認(rèn)值,可以減少用戶的輸入量。

3.1構(gòu)造函數(shù)使用默認(rèn)參數(shù)的構(gòu)造函數(shù)#include<iostream>usingnamespacestd;classBox{public:

Box(intw=10,inth=10,intlen=10);

intvolume();private:

intheight;

intwidth;

intlength;};Box::Box(int

w,int

h,int

len){height=h;width=w;length=len;}int

Box::volume(){return(height*width*length);}intmain(){Boxbox1;

cout<<"Thevolumeofbox1is"<<box1.volume()<<endl;Boxbox2(15);

cout<<"Thevolumeofbox2is"<<box2.volume()<<endl;Boxbox3(15,30);

cout<<"Thevolumeofbox3is"<<box3.volume()<<endl;Boxbox4(15,30,20);

cout<<"Thevolumeofbox4is"<<box4.volume()<<endl;return0;}使用默認(rèn)參數(shù)的構(gòu)造函數(shù)

#include<iostream.h>classcircle{private:floatradius;public://聲明構(gòu)造函數(shù)指定默認(rèn)參數(shù)floatarea(){returnradius*radius*3.14159;}};//定義函數(shù)voidmain(){circlec1(10.0),c2;

cout<<“c1的面積為”<<c1.area()<<endl;

cout<<“c2的面積為”<<c2.area()<<endl;}3.1構(gòu)造函數(shù)使用默認(rèn)參數(shù)的構(gòu)造函數(shù)#include<iostream.h>classcircle{private:floatradius;public:

circle(floatr=1.0);

//聲明構(gòu)造函數(shù)指定默認(rèn)參數(shù)floatarea(){returnradius*radius*3.14159;}};circle::circle(floatr)//定義函數(shù)時,可不再指定默認(rèn)參數(shù){radius=r;}voidmain(){circlec1(10.0),c2;

cout<<“c1的面積為”<<c1.area()<<endl;

cout<<“c2的面積為”<<c2.area()<<endl;}3.1構(gòu)造函數(shù)構(gòu)造函數(shù)中使用默認(rèn)參數(shù)的好處提供建立對象時的多種選擇,相當(dāng)于好幾個重載的構(gòu)造函數(shù)。即使在調(diào)用構(gòu)造時不提供參數(shù)也不會出錯,因為有默認(rèn)參數(shù)值參與對象初始化。當(dāng)每一個對象都是相同的初始值時,非常方便,用戶不需要輸入數(shù)據(jù)。3.1構(gòu)造函數(shù)默認(rèn)參數(shù)值的構(gòu)造函數(shù)使用注意何處指定默認(rèn)參數(shù)值?構(gòu)造函數(shù)的聲明處還是定義處?應(yīng)該在構(gòu)造函數(shù)的聲明處指定默認(rèn)參數(shù)值。因為類的聲明在頭文件中,用戶是看得見的,而在函數(shù)的定義處,用戶不一定看得見。一個類定義了全部是默認(rèn)參數(shù)的構(gòu)造函數(shù)后,不能再定義重載的構(gòu)造函數(shù)。否則會產(chǎn)生多義性,系統(tǒng)不知道調(diào)用哪一個。例如一個類有右邊形式的三個重載構(gòu)造函數(shù),若定義了如下對象: circlecircle1(); 它調(diào)用哪一個構(gòu)造函數(shù)呢?系統(tǒng)不能確定,從而引起混亂。circle(floatr=2.3);circle();circle(float);3.2析構(gòu)函數(shù)什么是析構(gòu)函數(shù)? 析構(gòu)函數(shù)(destructor)也是一個特殊函數(shù),它的作用與構(gòu)造函數(shù)相反,是在撤消對象占用的內(nèi)存前進行一些清理工作。析構(gòu)函數(shù)只能有一個。 析構(gòu)函數(shù)的名稱是類名的前面加一個取反符號“~”。我們在類的聲明中定義析構(gòu)函數(shù)。如果用戶不定義析構(gòu)函數(shù),系統(tǒng)便自動生成一個空的析構(gòu)函數(shù)。析構(gòu)函數(shù)特點:沒有返回類型;沒有函數(shù)參數(shù);不能被重載。3.2析構(gòu)函數(shù)什么時候運行析構(gòu)函數(shù)? 當(dāng)對象的生命結(jié)束時,會自動執(zhí)行它的析構(gòu)函數(shù)。具體而言,當(dāng)出現(xiàn)以下幾種情況,析構(gòu)函數(shù)就會被執(zhí)行。如果在函數(shù)中定義了一個對象,當(dāng)函數(shù)調(diào)用結(jié)束時,釋放對象,釋放對象前自動執(zhí)行析構(gòu)函數(shù)。

static局部對象在函數(shù)調(diào)用結(jié)束時,包含的對象不會被釋放,只在main函數(shù)結(jié)束或調(diào)用exit函數(shù)時,才調(diào)用static局部對象的析構(gòu)函數(shù)。如果定義了一個全局對象,,則在程序的流程離開其作用域時(如main函數(shù)結(jié)束,或exit語句),調(diào)用該全局對象的析構(gòu)函數(shù)。如果用new運算符動態(tài)地建立了一個對象,當(dāng)用delete運算符釋放對象時,先調(diào)用該全局對象的析構(gòu)函數(shù)。3.2析構(gòu)函數(shù)#include<iostream>#include<string>usingnamespacestd;classStudent{public:

Student(int

n,string

nam,chars){num=n;name=nam;sex=s;

cout<<"Constructorcalled."<<endl;}

~Student(){cout<<"Destructorcalled."<<endl;}voiddisplay(){cout<<"num:"<<num<<endl;

cout<<"name:"<<name<<endl;

cout<<"sex:"<<sex<<endl<<endl;}private:

intnum;stringname;charsex;};intmain(){Studentstud1(10010,"Wang_li",'f');stud1.display();Studentstud2(10011,"Zhang_fun",'m');stud2.display();return0;}析構(gòu)函數(shù)使用

#include<iostream.h>classbox{private:

intheight,width,length;public:

box(inth,intw,int

len){height=h;width=w;length=len;}//析構(gòu)函數(shù)intvolume(){returnheight*width*length;}};voidmain(){boxbox1(1,2,3);

cout<<“box1的體積為”<<box1.volume()<<endl;boxbox2(4,5,6);

cout<<“box2的體積為”<<box2.volume()<<endl;}3.2析構(gòu)函數(shù)#include<iostream.h>classbox{private:

intheight,width,length;public:

box(inth,intw,int

len){height=h;width=w;length=len;}~box()//析構(gòu)函數(shù){cout<<“Destructoringaobject”<<endl;}

intvolume(){returnheight*width*length;}};voidmain(){boxbox1(1,2,3);

cout<<“box1的體積為”<<box1.volume()<<endl;boxbox2(4,5,6);

cout<<“box2的體積為”<<box2.volume()<<endl;}析構(gòu)函數(shù)使用3.3調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)的順序調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)的順序 先構(gòu)造的后析構(gòu),后構(gòu)造的先析構(gòu)。#include<iostream.h>classbox{private:

intheight,width,length;public:

box(inth,intw,int

len){height=h;width=w;length=len;

cout<<“Constructoraobject”<<endl;}

~box()//析構(gòu)函數(shù){cout<<“Destructoringaobject”<<endl;}

int

vol(){returnheight*width*length;}};voidfn(){boxb1(2,2,2);

cout<<“b1=”<<b1.vol()<<endl;

staticboxb2(3,3,3);cout<<“b2=”<<b2.vol()<<endl;}voidmain(){fn();boxb3(1,2,3);

cout<<“b3=”<<b3.vol()<<endl;boxb4(4,5,6);

cout<<“b4=”<<b4.vol()<<endl;}//fn結(jié)束不析構(gòu)b2,直到main結(jié)束3.4對象數(shù)組數(shù)組不僅可以由簡單變量組成,也可以由對象組成,即每一個數(shù)組元素都是同類的對象。#include<iostream>usingnamespacestd;classBox{public:

Box(inth=10,intw=12,intlen=15):

height(h),width(w),length(len){}

intvolume();private:

intheight;

intwidth;

intlength;};int

Box::volume(){return(height*width*length);}

intmain(){Boxa[3]={Box(10,12,15),Box(15,18,20),Box(16,20,26)};

cout<<"volumeofa[0]is"<<a[0].volume()<<endl;

cout<<"volumeofa[0]is"<<a[1].volume()<<endl;

cout<<"volumeofa[0]is"<<a[2].volume()<<endl;return0;}3.4對象數(shù)組 數(shù)組不僅可以由簡單變量組成,也可以由對象組成,即每一個數(shù)組元素都是同類的對象。 例如,一個班有30人,每個學(xué)生的屬性包括學(xué)號、姓名、性別。我們建立起學(xué)生類后,為每個學(xué)生建立一個對象,需要分別取30個對象名,很不方便。較好的做法是,定義一個“學(xué)生類”,的對象數(shù)組,每一個數(shù)組元素是一個“學(xué)生類”的對象。

用指定參數(shù)的構(gòu)造函數(shù)初始化數(shù)組#include<iostream.h>#include<string.h>classstudent{private:

intnum;charname[10];charsex;public:student(intn,stringnam,chars){num=n;

strcpy(name,nam);sex=s;

cout<<“Constructorcalled.“<<endl;}~student(){cout<<“Destructorcalled.”<<endl;}voiddisplay();};voidstudent::display(){cout<<“num:”<<num<<endl;

cout<<“name:”<<name<<endl;

cout<<“sex:”;if(sex==0){cout<<“男”<<endl;}else{cout<<“女”<<endl;}}voidmain()//用指定參數(shù)的構(gòu)造函數(shù)初始化數(shù)組

cout<<“第一個學(xué)生";stud[0].display();

cout<<“第二個學(xué)生";stud[1].display();

cout<<“第三個學(xué)生";stud[2].display();}3.4對象數(shù)組#include<iostream>#include<string>usingnamespacestd;classstudent{private:

intnum;stringname[10];charsex;public:student(intn,stringnam,chars){num=n;name=nam;sex=s;

cout<<“Constructorcalled.“<<endl;}~student(){cout<<“Destructorcalled.”<<endl;}voiddisplay();};voidstudent::display(){cout<<“num:”<<num<<endl;

cout<<“name:”<<name<<endl;

cout<<“sex:”;if(sex==0){cout<<“男”<<endl;}else{cout<<“女”<<endl;}}voidmain(){studentstud[3]={student(1001,“張三",1),student(1002,“李四",0),student(1003,“王五",0)};//用指定參數(shù)的構(gòu)造函數(shù)初始化數(shù)組

cout<<“第一個學(xué)生";stud[0].display();

cout<<“第二個學(xué)生";stud[1].display();

cout<<“第三個學(xué)生";stud[2].display();}3.5對象指針指向?qū)ο蟮闹羔? 創(chuàng)建一個類的對象時,系統(tǒng)會為每一個對象分配一定的存儲空間,以存放成員。對象空間的起始地址就是對象的指針??梢远x一個指針,用來存放對象的指針:訪問成員的方法:(*pt).hour,(*pt).put()

或者:pt->hour,pt->put()classTime{public:

inthour,minute,sec;voidput(){hour=12;minute=0;sec=0;}};voidmain(){Time*pt,t1;pt=&t1;p1.put();

cout<<pt->hour<<“:”<<pt->minute<<“:”<<sec<<endl;

cout<<(*pt).hour<<“:”<<(*pt).minute<<“:”<<(*pt).sec<<endl;}3.5對象指針指向?qū)ο髷?shù)據(jù)成員的指針 定義一個指向?qū)ο髷?shù)據(jù)成員的指針變量的方法和前面介紹的定義指向普通變量的指針變量方法相同。

定義格式:數(shù)據(jù)類型名*指針變量名;例如:

int*pl;//定義指向整形數(shù)據(jù)的指針變量

pl=&t1.hour;//將t1的數(shù)據(jù)成員hour地址賦給指針pl,使其指向t1.hour

cout<<*pl<<endl;//輸出t1.hour的值

3.5對象指針指向?qū)ο蟪蓡T函數(shù)的指針 定義指向?qū)ο蟪蓡T函數(shù)的指針變量的方法和定義指向普通函數(shù)的指針變量的方法有所不同。

指向普通函數(shù)的指針變量的定義方法:

返回數(shù)據(jù)類型(*指針變量名)(參數(shù)表列);例:void(*p)();//p是指向void類型函數(shù)的指針變量

p=fun;//將fun函數(shù)的入口地址賦給指針變量p(*p)();//調(diào)用fun函數(shù)而定義一個指向?qū)ο蟪蓡T函數(shù)的指針變量則不能這樣:

p=t1.put;//出現(xiàn)編譯錯誤,不知道t1.put所屬的類3.5對象指針定義指向公用成員函數(shù)的指針變量方法:

返回數(shù)據(jù)類型(類名::*指針變量名)(參數(shù)表列);例:void(Time::*p2)();//Time::*p2的括號必須加上令指針變量指向一個公用成員函數(shù)的方法: 指針變量名=&類名::成員函數(shù)名;例:p2=&Time::put;3.5對象指針#include<iostream.h>classTime{public:

inthour,minute,sec;Time(inth,intm,ints){hour=h;minute=m;sec=s;}voidget_Time(){cout<<hour<<“:”<<minute<<“:”<<sec<<endl;}};voidmain(){Timet1(10,12,56);

int*pl=&t1.hour;//定義指向整形數(shù)據(jù)的指針,指向t1.hour

cout<<*p1<<endl;t1.get_Time();//調(diào)用t1的成員函數(shù)Time*p2=&t1;

//定義指向Time類對象的指針變量t2,并指向t1p2->get_Time();//調(diào)用p2所指對象的成員函數(shù)void(Time::*p3)();

//定義指向Time類公用成員函數(shù)的指針變量p3p3=&Time::get_Time;

//使p3指向Time類公用成員函數(shù)get_Time()(t1.*p3)();//調(diào)用p3所指的成員函數(shù)t1.get)Time()}3.5對象指針this指針 通過第二章的學(xué)習(xí)我們知道,多個同類對象在內(nèi)存中是共享成員函數(shù)的,以節(jié)省內(nèi)存空間。

C++在每一個成員函數(shù)中都包含一個特殊的指針,這個指針的名字是固定的,成為“this”。它是指向本對象的指針,它的值是當(dāng)前被調(diào)用的成員函數(shù)所在對象的起始地址。 例如,當(dāng)a的成員函數(shù)調(diào)用數(shù)據(jù)成員a.volume時,編譯系統(tǒng)就把對象a的起始地址賦給this指針,于是在成員函數(shù)引用數(shù)據(jù)成員時,就按照this的指向找到對象a的數(shù)據(jù)成員。3.5對象指針 比如下列涉及數(shù)據(jù)成員的運算的返回語句:

returnlength*width*height; 實際上C++處理為:

return(this->length)*(this->width)*(this->height); 也可以寫成如下形式:

return((*this).length*(*this).width*(*this).height); 但不能寫成:

return((*this.length)*(*this.width)*(*this.height));//錯誤 因為“.”操作符的優(yōu)先級高于指針運算符“*”,(*this.length)就相當(dāng)于*(this.length),而this.length

是不合法的,編譯出錯(應(yīng)該是this->length)。3.6共用數(shù)據(jù)的保護

C++采用了不少的數(shù)據(jù)保護措施。最常用的,是將數(shù)據(jù)成員設(shè)置成私有數(shù)據(jù)(private),以增加數(shù)據(jù)的安全性和私密性。 但是,有時候要求數(shù)據(jù)在能共享的前提下能不能被篡改,我們就需要借助其他手段了。 什么手段呢?可以采用const,即把要保護的數(shù)據(jù)定義為常量。3.6共用數(shù)據(jù)的保護常對象 在定義對象時指定對象為常對象。常對象中的數(shù)據(jù)成員為常變量,并且必須要有初值:

Timeconstt1(12,34,56);

這樣,在所有的場合中,對象t1的所有數(shù)據(jù)成員都被保護了,不能被修改。因此,凡是希望數(shù)據(jù)成員不能被改變的對象,可以聲明為常對象。其聲明格式為: 類名const對象名(參數(shù)表列); 或者:

const類名對象名(參數(shù)表列); 兩者等價。3.6共用數(shù)據(jù)的保護 如果一個對象被定義成常對象,那么不能調(diào)用該對象的非const型成員函數(shù),當(dāng)然,系統(tǒng)隱含調(diào)用的構(gòu)造函數(shù)和析構(gòu)函數(shù)除外。 Timeconstt1(12,34,56);//定義t1為常對象 t1.get_Time();//錯誤,get_Tiem()不是const型,不能調(diào)用 為什么會這樣?因為成員函數(shù)有可能修改數(shù)據(jù)成員,而成員函數(shù)的定義可能和成員函數(shù)的聲明不在同一文件,系統(tǒng)沒法檢測。所以,系統(tǒng)只能統(tǒng)一攔截,不讓用戶調(diào)用常對象的成員函數(shù),除非該成員函數(shù)被聲明成const類型。3.6共用數(shù)據(jù)的保護 怎樣才能引用常對象的成員函數(shù)呢?常成員函數(shù):

函數(shù)返回類型函數(shù)名(參數(shù)表列)

const;

比如:voidget_Time()const;//將函數(shù)聲明成const類型 常成員函數(shù)可以訪問常對象中的數(shù)據(jù)成員,但仍然不準(zhǔn)修改它們。

有時候編程要求必須修改某個常對象中的數(shù)據(jù)成員,如某個計數(shù)器count,ANSIC++對此做了特殊的處理,將該數(shù)據(jù)成員聲明為mutable,如:

mutable

intcount; 這樣,常對象的數(shù)據(jù)成員count,就可以用常成員函數(shù)來訪問和修改了。3.6共用數(shù)據(jù)的保護常對象成員

常數(shù)據(jù)成員:其作用和用法與一般常變量相似,在類的聲明中,用關(guān)鍵詞const來聲明常數(shù)據(jù)成員,例如:

constinthour; 注意:常數(shù)據(jù)成員的初始化,不能采用在構(gòu)造函數(shù)中對常數(shù)據(jù)成員賦予初值的方法,只能通過構(gòu)造函數(shù)的參數(shù)初始化表對常數(shù)據(jù)成員進行初始化。 在類外定義構(gòu)造函數(shù),初始化形式為:

Time::Time(inth):hour(h){} 在類中聲明了某一個數(shù)據(jù)成員為常數(shù)據(jù)成員后,該類的所有對象中的該數(shù)據(jù)成員的值是不可改變的,但可以是不同的(由每個對象的參數(shù)初始化表決定)。3.6共用數(shù)據(jù)的保護

常成員函數(shù)

一般的成員函數(shù)可以引用本對象中的非const數(shù)據(jù)成員,也可以修改它們。但如果成員函數(shù)聲明為常成員函數(shù),則只能引用本對象中的數(shù)據(jù)成員,而不能修改它們。如

voidget_Time()const;//const位置在最后

const是函數(shù)類型的一部分,在聲明函數(shù)和定義函數(shù)時都要用到const關(guān)鍵字。 常成員函數(shù)可以引用常數(shù)據(jù)成員,也可以引用非const數(shù)據(jù)成員;而常數(shù)據(jù)成員可以被常成員函數(shù)引用,也可以被非const成員函數(shù)引用。夠亂的,見90頁表總結(jié)。3.6共用數(shù)據(jù)的保護數(shù)據(jù)成員非const成員函數(shù)const成員函數(shù)非const數(shù)據(jù)成員可引用,可修改可引用,不可修改const數(shù)據(jù)成員可引用,不可修改可引用,不可修改常對象的數(shù)據(jù)成員不可引用,不可修改可引用,不可修改3.6共用數(shù)據(jù)的保護怎樣使用常成員函數(shù)呢?類中如果一些數(shù)據(jù)成員需要保護,另一些數(shù)據(jù)成員不需保護,我們就將需要保護的數(shù)據(jù)成員聲明為const,以保證其值不被改變。類中如果所有數(shù)據(jù)成員都需保護,可以將所有數(shù)據(jù)成員都聲明成const,本對象的任何成員函數(shù),都只能引用,不能改變它們?;蛘邔⑦@些數(shù)據(jù)成員所屬的對象聲明成const,只讓本對象的const成員函數(shù)可引用,但不能改變。如果一個對象被定義成了常對象,只能調(diào)用其中的const成員函數(shù),不能調(diào)用非const成員函數(shù)。常成員函數(shù)不能調(diào)用另一個非const成員函數(shù)3.6共用數(shù)據(jù)的保護對象的常引用 前面講過,引用主要是用于函數(shù)調(diào)用,將改變后的變量值帶回到被調(diào)用的函數(shù)外。 但如果不希望在函數(shù)中修改參數(shù),可以把引用型形參定義成const型:

函數(shù)返回類型函數(shù)名(const形參類型&形參名); 則在函數(shù)中不能改變形參值,也就不能改變對應(yīng)的實參值。什么時候使用常引用?使用常引用作為函數(shù)參數(shù),既能保證數(shù)據(jù)安全,不被修改;調(diào)用函數(shù)時又能不必建立實參的拷貝,提高了程序運行效率,節(jié)省了內(nèi)存空間。對象的常引用#include<iostream>usingnamespacestd;classTime{public:

Time(int,int,int);

inthour;

intminute;

intsec;};

Time::Time(int

h,int

m,ints){hour=h;minute=m;sec=s;}

voidfun(constTime&t){t.hour=18;}intmain(){Timet1(10,13,56);fun(t1);

cout<<t1.hour<<endl;return0;}3.7對象的動態(tài)建立和釋放問題的提出:前面我們所學(xué)創(chuàng)建對象的方法都是靜態(tài)的,它們在程序運行過程中所占用的內(nèi)存空間不能被釋放。比如,在一個函數(shù)中定義了一個對象,只有在函數(shù)結(jié)束時,該對象才能被釋放。 有時候,人們希望對象的創(chuàng)建和釋放是在程序運行時,由運行程序的人決定C++語言用new、delete這兩個運算符來實現(xiàn)。內(nèi)存的分配和釋放,也用來實現(xiàn)對象的建立與撤消。3.7對象的動態(tài)建立和釋放動態(tài)建立對象的方法: 如果已經(jīng)定義了一個Box類,可以用new運算符動態(tài)地創(chuàng)建一個Box對象:

newBox;

Box*pt;//定義一個指向Box類對象的指針ptpt=newBox;//創(chuàng)建一個Box對象,將新對象的指針值賦給ptcout<<pt->height<<endl;3.7對象的動態(tài)建立和釋放 用new動態(tài)創(chuàng)建的對象一般沒有對象名,只能通過指針訪問。 在執(zhí)行new運算時,如果內(nèi)存不足,則創(chuàng)建失敗。大多數(shù)C++編譯系統(tǒng)都讓new返回一個0指針,表示內(nèi)存不足,操作失敗。動態(tài)撤消對象的方法:由new創(chuàng)建的對象不再需要時,可以由delete運算符釋放。釋放方法為:

deletept;析構(gòu)函數(shù)調(diào)用?3.8對象的賦值與復(fù)制對象的復(fù)制問題的提出:有時需要多個完全相同的對象,可不可以用克隆的方法呢?

C++可以根據(jù)一個已知的對象快速地復(fù)制出多個完全相同的對象。比如:

Boxbox2(box1);

其作用就是對象的克隆,即用一個已知的對象box1復(fù)制出一個完全相同的新對象box2。對象復(fù)制的格式: 類名被克隆出來的新對象名(已有的對象名);3.8對象的賦值與復(fù)制 從上面的一般形式可以看出,復(fù)制對象是一種特殊的構(gòu)造對象方法,其構(gòu)造參數(shù)不是一般變量,而必須是一個對象!請看:

//復(fù)制構(gòu)造函數(shù)

Box::Box(constBox&b) {height=b.height; width=b.width; height=b.height; }

復(fù)制構(gòu)造函數(shù)也是構(gòu)造函數(shù),它只有一個參數(shù),這個參數(shù)是本類已有對象,而且采用常引用形式,使參數(shù)不能被改變。復(fù)制構(gòu)造函數(shù)的作用是將實參對象的各個數(shù)據(jù)成員值一一賦予給新的對象中對應(yīng)的數(shù)據(jù)成員。3.8對象的賦值與復(fù)制

C++還使用另一種方便的對象復(fù)制形式,形式為:

類名目標(biāo)對象名=源象名; 如:

Boxbox2=box1,box3=box2;對象的賦值與復(fù)制的不同點對象的賦值:是在已經(jīng)存在的對象之間進行數(shù)據(jù)賦值,因此必須先定義,再賦值;參數(shù)表是一般變量對象的復(fù)制:從無到有地建立一個相同的新對象,參數(shù)只有一個,而且是已有的同類對象。兩者形式的不同: 類名(形參表列);//普通構(gòu)造函數(shù)的聲明 類名(類名&對象名);//復(fù)制構(gòu)造函數(shù)的聲明3.8對象的賦值與復(fù)制intmain(){Boxbox1(15,30,25);

cout<<"Thevolumeofbox1is"<<box1.volume()<<endl;Boxbox2=box1,box3=box2;

cout<<"Thevolumeofbox2is"<<box2.volume()<<endl;

cout<<"Thevolumeofbox3is"<<box3.volume()<<endl;return0;}

intmain(){Boxbox1(15,30,25),box2;

cout<<"Thevolumeofbox1is"<<box1.volume()<<endl;box2=box1;

cout<<"Thevolumeofbox2is"<<box2.volume()<<endl;return0;}//賦值3.8對象的賦值與復(fù)制什么時候使用復(fù)制構(gòu)造函數(shù)?程序中需要建立一個對象,并用另一個已知對象初始化它,系統(tǒng)自動調(diào)用復(fù)制構(gòu)造函數(shù);當(dāng)函數(shù)的參數(shù)是類的對象時,系統(tǒng)自動調(diào)用復(fù)制構(gòu)造函數(shù);

voidmain() {Boxb1(12,13,15); func(b1);}當(dāng)函數(shù)的返回值是類的對象,系統(tǒng)自動調(diào)用復(fù)制構(gòu)造函數(shù)

Boxf() {Boxb1(12,14,16);

returnb1;}//返回值是Box類的對象 voidmain() {Boxb2;

b2=f();}//f函數(shù)返回Box類的臨時對象,并將它賦值給b2

3.9靜態(tài)成員 在C語言中,如果想在多個函數(shù)中共享一個變量值,我們一般用全局變量。但由于全局變量破壞了封裝性,安全得不到保證,在C++中不提倡使用全局變量,我們可以使用靜態(tài)的數(shù)據(jù)成員來達到這個目的。靜態(tài)數(shù)據(jù)成員靜態(tài)數(shù)據(jù)成員以

static關(guān)鍵字定義。例如:

classstudent {public:

intdisplay(); private:

static

intcount; charname[10];

intage; };3.9靜態(tài)成員 將對象中的count數(shù)據(jù)成員定義成static型,它就被同一種類的各個對象所共有,而不只屬于某一個對象。靜態(tài)數(shù)據(jù)成員只占份內(nèi)存空間,而不是各個對象個擁有一份內(nèi)存空間!每個對象都可以引用這個靜態(tài)數(shù)據(jù)成員。靜態(tài)數(shù)據(jù)成員的值對各個對象都是一樣的。如果改變它的值,則在各個對象中這個數(shù)據(jù)成員的值都同時改變。3.9靜態(tài)成員說明:在為對象分配空間時,不分配靜態(tài)數(shù)據(jù)成員的空間,因為它不屬于任何對象。只要類中定義了靜態(tài)數(shù)據(jù)成員,即使不定義對象,編譯系統(tǒng)也要為靜態(tài)數(shù)據(jù)成員開辟內(nèi)存空間。C語言中,我們知道,如果在一個函數(shù)中定義了一個靜態(tài)變量,在函數(shù)結(jié)束時該靜態(tài)變量不被釋放,并保留其值。靜態(tài)數(shù)據(jù)成員也是這樣,它不隨對象的建立而分配空間,也不隨對象的撤消而釋放空間,其值也被保留。靜態(tài)數(shù)據(jù)成員在程序被編譯時就分配了空間,在程序結(jié)束時,才釋放空間。靜態(tài)數(shù)據(jù)成員可以被初始化,但只能在類體之外初始化:

數(shù)據(jù)類型類名::靜態(tài)數(shù)據(jù)成員名=初值; 不必在初始化語句中加static關(guān)鍵字,不能用參數(shù)初始化表初始化靜態(tài)數(shù)據(jù)成員:

student(intc,char*p,inta):count(c){}

//錯誤,count是靜態(tài)數(shù)據(jù)成員3.9靜態(tài)成員靜態(tài)數(shù)據(jù)成員既可以通過類名引用,也可以通過對象名引用。#include<iostream>usingnamespacestd;classBox{public:

Box(int,int);

intvolume();staticintheight;

intwidth;

intlength;};Box::Box(int

w,int

len){width=w;length=len;}int

Box::volume(){return(height*width*length);}int

Box::height=10;intmain(){Boxa(15,20),b(20,30);

cout<<a.height<<endl;

cout<<b.height<<endl;

cout<<Box::height<<endl;

cout<<a.volume()<<endl;return0;}3.9靜態(tài)成員#include<iostream.h>#include<string.h>classStudent{public:

staticintcount;

//靜態(tài)數(shù)據(jù)成員

charname[40];

Student(char*pN="noname"){cout<<"Createonestudent"<<pN<<"\n";

strcpy(name,pN);

count++;

cout<<count<<endl;}~Student(){cout<<"destructonestudent“<<name<<"\n";

count--;

cout<<count<<endl;}};intStudent::count=0;

voidmain(){Students1("zhangsan");

cout<<"Student::count“<<Student::count<<endl;Students2("lisi");

cout<<"Student::count“<<Student::count<<endl;}3.9靜態(tài)成員靜態(tài)成員函數(shù)在類的定義中,成員函數(shù)前如果加了static限定詞,該成員函數(shù)就成為靜態(tài)成員函數(shù)。例:

staticintvolume();用途:靜態(tài)成員函數(shù)的作用不是為了對象之間的溝通,主要是為了引用本類中的靜態(tài)數(shù)據(jù)成員。它可以直接引用本類的靜態(tài)數(shù)據(jù)成員。靜態(tài)成員函數(shù)與普通成員函數(shù)的區(qū)別:靜態(tài)成員函數(shù)沒有this指針,由此決定靜態(tài)成員函數(shù)不能訪問本類中的非靜態(tài)數(shù)據(jù)成員,除非用“對象名.非靜態(tài)數(shù)據(jù)成員”的形式。

靜態(tài)成員函數(shù)示例3.11

#include<iostream>usingnamespacestd;classStudent{public:

Student(int,int,int);voidtotal();staticfloataverage();private:

intnum;

intage;floatscore;staticfloatsum;staticintcount;};

Student::Student(int

m,int

a,ints){num=m;age=a;score=s;}voidStudent::total(){sum+=score;count++;}

floatStudent::average(){return(sum/count);}floatStudent::sum=0;int

Student::count=0;intmain(){Studentstud[3]={Student(1001,18,70),Student(1002,19,79),Student(1005,20,98)};

intn;

cout<<"pleaseinputthenumberofstudents:";

cin>>n;

for(inti=0;i<n;i++)

stud[i].total();

cout<<"Theaveragescoreof"<<n<<"studentsis"<<stud[0].average()<<endl;return0;}Student::average()3.9靜態(tài)成員#include<iostream.h>#include<string.h>classStudent{protected:

staticintcount;

//靜態(tài)數(shù)據(jù)成員

charname[40];public:

Student(char*pN="noname"){cout<<"Createonestudent"<<pN<<"\n";

strcpy(name,pN);

count++;

cout<<count<<endl;}~Student(){cout<<"destructonestudent“<<name<<"\n";

count--;

cout<<count<<endl;}

staticintnumber()//靜態(tài)成員函數(shù)

{returncount;}//直接引用本類的靜態(tài)數(shù)據(jù)成員};intStudent::count=0;

voidfn(){Students1("zhangsan");Students2("lisi");

cout<<Student::number()<<endl;

cout<<s1.number()<<endl;

cout<<s2.number()<<endl;}voidmain(){fn();

cout<<"Student::number“<<Student::number()<<endl;}3.10友元 類具有封裝性,類中的私有數(shù)據(jù)只有通過該類的成員函數(shù)才可以訪問。如果在程序中需要訪問類的私有成員,就必須通過對象來調(diào)用類的成員函數(shù),頻繁調(diào)用成員函數(shù)將影響程序運行效率。 為解決上述問題,C++提供一種友元機制,友元可以不通過調(diào)用成員函數(shù)就可以直接訪問類的私有數(shù)據(jù),以提高程序運行效率。 友元機制在數(shù)據(jù)封裝這堵不透明的墻上開了一個小孔,友元的使用要慎重。 友元可以是一個普通函數(shù),可以是一個類的成員函數(shù),也可以是一個類。#include<iostream>usingnamespacestd;classTime{public:

Time(int,int,int);

friendvoiddisplay(Time&);private:

inthour;

intminute;

intsec;};

Time::Time(int

h,int

m,ints){hour=h;minute=m;sec=s;}voiddisplay(Time&t){

cout<<t.hour<<":"<<t.minute<<":"<<t.sec<<endl;}

intmain(){Timet1(10,13,56);display(t1);return0;}3.10友元友元成員函數(shù):friend函數(shù)可以是另一個類中的成員函數(shù)。#include<iostream.h>classtwo;classone{private:

intvalue;public:

one(intv){value=v;}voidsettwo(two&ob);voidshow(){cout<<"classone'sprivatevalue=“<<value<<endl;}};classtwo{private:

intvalue;public:voidshow(){cout<<"classtwo'sprivatevalue=“<<value<<endl;}

friendvoidone::settwo(two&ob);};voidone::settwo(two&ob){ob.value=value;}voidmain(){oneob1(2);twoob2;ob1.settwo(ob2);ob1.show();ob2.show();}3.10友元友元類:

當(dāng)說明一個類為另一個類的友元時,友元類中的所有成員函數(shù)都是另一個類的友元函數(shù)。例如:#include<iostream.h>classX{public:

friendclassY;//類Y是類X的友元類

voidset(inti

){x=i;}voiddisplay(){cout<<“x=”<<x<<“,”<<“y=”<<y<<endl;}private:

intx;staticinty;//靜態(tài)數(shù)據(jù)說明};classY{public:Y(int

i,intj);voiddisplay();private:Xa;//數(shù)據(jù)成員為類X的對象};intX::y=10;//靜態(tài)數(shù)據(jù)定義并初始化Y::Y(int

i,intj){a.x=i;X::y=j;}voidY::display(){cout<<“x=”<<a.x<<“,”<<“y=”<<X::y<<endl;}voidmain(){Xb;b.set(5);

b.display();Yc(6,9);

c.display();

b.display();}結(jié)果:x=5,y=10x=6,y=9x=5,y=93.11

類模板(ClassTemplates)為什么要使用類模板 如果要對功能相同、僅類的數(shù)據(jù)類型不同的各種情況,都重新定義一種新的類型,會產(chǎn)生較大的重復(fù)。例如:

classcompare_int{public:

compare_int(inta,intb){x=a;y=b;}

intmax(){return(x>y)?x:y;}private:

int

x,y;};classcompare_char{public:

compare_char(chara,charb){x=a;y=b;}charmax(){return(x>y)?x:y;}private:charx,y;};voidmain(){compare_intc1(5,6);

cout<<c1.max()<<endl;

compare_charc2(‘a(chǎn)’,‘f’);

cout<<c2.max()<<endl;}3.11

類模板(ClassTemplates)類模板的定義: 為解決這一問題,C++引進類模板的概念。我們在類的聲明前先加一行模板關(guān)鍵字。它用一個通用參數(shù)T來替代不同的數(shù)據(jù)類型。類模板的定義格式為:template<class類型參數(shù)名>class<類名>{//類體說明}; 其中template是關(guān)鍵字;<class類型參數(shù)名>中可以有多個參數(shù),其間用逗號分隔。使用類模板定義對象的: 類模板名<實際數(shù)據(jù)類型名>對象名(實參列表); 例如:下面是一個數(shù)組類模板的例子#include<iostream.h>template<classT>classcompare{public:compare(Ta,Tb){x=a;y=b;}

Tmax(){return(x>y)?x:y;}private:

T

x,y;};voidmain(){compare<int>cmp1(3,7);

cout<<cmp1.max()<<“是兩個整數(shù)中最大的數(shù)”<<endl;

compare<char>cmp2(‘a(chǎn)’,’g’);

cout<<cmp2.max()<<“是兩個字符中最大的字符”<<endl;

compare<float>cmp3(1.0,3.0);

cout<<cmp3.max()<<“是兩個浮點數(shù)中最大的數(shù)”<<endl;}習(xí)題2習(xí)題3#include<iostream>usingnamespacestd;classDate{public:Date(int=1,int=1,int=2005);voiddisplay();private:intmonth;intday;intyear;};

Date::Date(intm,intd,inty):month(m),day(d),year(y){}習(xí)題6習(xí)題7-1#include<iostream>usingnamespacestd;classStudent{public:

Student(int

n,float

s):num(n),score(s){}voidchange(int

n

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論