C++面向對象程序設計第三章類與對象課件_第1頁
C++面向對象程序設計第三章類與對象課件_第2頁
C++面向對象程序設計第三章類與對象課件_第3頁
C++面向對象程序設計第三章類與對象課件_第4頁
C++面向對象程序設計第三章類與對象課件_第5頁
已閱讀5頁,還剩353頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第三章類與對象

第三章類與對象

學習目標

(1)理解類的概念,掌握類的定義方法(2)理解對象與類的關系,掌握對象的創(chuàng)建和使用方法(3)掌握構造函數、析構函數的概念和使用方法(4)掌握拷貝構造函數的使用方法(5)掌握對象數組和對象指針的特點和使用方法(6)掌握函數調用中參數的傳遞方式(7)理解類的組合的特點學習目標

(1)理解類的概念,掌握類的定義方法

3.1類和對象的概念

類是對一組具有共同屬性特征和行為特征的實體(對象)的抽象,它將相關數據及對這些數據的操作組合在一起。

對象是封裝了數據和可以施加在這些數據上的操作的封裝體,它是類的實際變量,即類的實例。

3.1類和對象的概念類

3.1.1類的基本概念

類(class)是面向對象系統(tǒng)中最基本的組成元素,是一種自定義數據類型。在C++中,類是一些具有相同屬性和行為的對象的抽象。

3.1.1類的基本概念類(class

3.1.2

對象的基本概念

對象是某個特定類所描述的實例。現實世界中的任何一種事物都可以看成一個對象(Object),即萬物皆對象。

3.1.2對象的基本概念對象是某個特

3.2類的定義

類的定義包括兩部分:類頭和類體。

類頭由關鍵字“class”及其后面的類名構成;

類體用于對類的數據成員和成員函數進行聲明,并指定相應成員的訪問級別。

3.2類的定義類的定義包括兩部分:類

3.2.1類的定義格式class類名{private:

數據成員或成員函數

protected:

數據成員或成員函數

public:

數據成員或成員函數};

3.2.1類的定義格式class類名{

說明:

(1)class是聲明類的關鍵字,class后跟類名。類名的首字符通常采用大寫字母。

(2)類的成員包括數據成員和成員函數兩類。

(3)類聲明中的private、protected和public關鍵字稱為訪問權限符,它規(guī)定了類中成員的訪問屬性。

(4)在C++中,由于類是一種數據類型,系統(tǒng)不會為其分配存儲空間,所以不能在類聲明中給數據成員賦初值。

(5)類聲明完成后一定要以“;”結束。

說明:

【例3-1】聲明一個學生類

分析:每個學生都有學號、姓名和性別;對于學生的基本操作有輸入、輸出信息等。

【例3-1】聲明一個學生類

classStudent

//聲明類{private://訪問權限:私有成員charstudentNo[10];//屬性,數據成員,表示學號charstudentName[20];//屬性,數據成員,表示姓名charstudentSex[6];//屬性,數據成員,表示性別public://訪問權限:公有成員Student();//行為,成員函數的原型聲明,表示構造函數voidinput();voidprint();};

//類聲明結束

classStudent

3.2.2類的成員

對于C++,類中共有兩類成員:1)代表對象屬性的數據成員2)代表實現對象行為的成員函數

3.2.2類的成員對于C++,類中共有兩

3.2.3類成員訪問控制權限public(公有類型)、private(私有類型)和protected(保護類型)。1、public(公有類型)public聲明成員為公有成員。具有這個訪問控制級別的成員是完全公開的,即該成員不但可以被它所在類的成員函數及該類的友元函數訪問,而且也可以被和該類對象處在同一作用域內的任何函數訪問。

3.2.3類成員訪問控制權限public

【例3-2】具有public訪問權限的成員的應用#include"stdafx.h"#include"iostream"usingnamespacestd;classLimit{public://聲明類的公有成員charname[30];voidaccept(){ cout<<"\nEnteryourname,please:"; cin>>name;//類的成員函數訪問類的公有數據成員 cout<<"\nYournameis:"<<name<<endl;}};voidmain(){Limitc;//定義類的對象c.accept();//通過對象訪問類的公有成員函數cout<<<<endl;//通過對象訪問類的公有數據成員

【例3-2】具有public訪問權限的成員的

說明:

(1)在一個項目中的每一個.cpp文件都包含有大量的相同的MFC(MicrosoftFoundationClassLibrary)標準頭文件,這些頭文件一般都不會改變,并且都非常大,即使有一個快速的處理程序,完成其編譯也要花費相當長的時間。因此,對這些頭文件進行預先編譯,以后該工程編譯時,不再編譯這部分頭文件,僅僅使用預編譯的結果,就可以節(jié)省大量的編譯時間?!皊tdafx.h”文件中就包含了這些必要的標準頭文件。#include"stdafx.h"的作用就是令編譯器編譯出一個stdafx.obj預編譯頭文件。因此,一般.cpp文件的第一條語句都是#include"stdafx.h"。

說明:

(2)在C++中,_tmain是主函數名(也可以與c一樣是main),每一個項目中有且僅有一個主函數,它表示程序執(zhí)行的開始點。

(2)在C++中,_tmain是主函數名(也

2、private(私有類型)private聲明成員為私有成員。具有這個訪問控制級別的成員對類外是完全保密的,即只能被它所在類中的成員函數和該類的友元函數訪問。

2、private(私有類型)

【例3-3】具有private訪問權限的成員的應用#include"stdafx.h"#include"iostream"usingnamespacestd;

classLimit{private://聲明類的私有成員floatimprest;voidwarning(){ cout<<"Warning!";}

【例3-3】具有private訪問權限的成員的應用

public://聲明類的公有成員voidaccept(){cout<<"\nEnteryourimprest,please:\t";cin>>imprest; cout<<"\nYourimprestis:\t"<<imprest;//類的私有數據成員可以被本類的成員函數訪問}voiddisplay(){cout<<"\nNow,yourimprestis:\t"<<imprest;warning();//類的私有成員函數可以被本類的成員函數訪問}};

public:

voidmain(){Limitc;c.accept();c.display();c.imprest=3.3f;

//錯誤,不能通過對象訪問類的私有數據成員c.warning();

//錯誤,不能通過對象訪問類的私有成員函數}

voidmain()

3、protected(保護類型)protected聲明成員為保護成員。具有這個訪問控制級別的成員,外界是無法直接訪問的。它只能被它所在類及從該類派生的子類的成員函數及友元函數訪問。

3、protected(保護類型)

例【3-4】具有protected訪問權限的成員的應用#include"stdafx.h"……classLimit{protected://聲明類的保護成員 floatimprest; voidwarning() { cout<<"Warning!"; }

例【3-4】具有protected訪問權限的成員的

public: voidaccept() { …… cin>>imprest;//類的保護數據成員可以被本類的成員函數訪問 cout<<"\nYourimprestis:\t"<<imprest; } ……};

public:

classExtends:publicLimit

//聲明類Limit的派生類Extends{public:voidext_display(){cout<<"\nthedisplayofextendsclassis:";warning();//訪問從基類繼承的保護成員函數}};

classExtends:publicLimi

voidmain(){Limitc;c.accept();c.imprest;//錯誤類的對象不能訪問類的保護數據成員c.warning;//錯誤類的對象不能訪問類的保護成員函數……}

voidmain()

public、protected和private三種類成員的可訪問性public、protected和private三種類成員

3.2.4成員函數的實現方式

類的成員函數也是函數的一種,它與一般函數的區(qū)別是:它屬于一個特定的類,并且它必須被指定為private、public或protected三種訪問權限中的一種。

在使用類的成員函數時,要注意它的訪問權限(它能否被訪問),以及它的作用域(類函數能在什么范圍內被訪問)。

3.2.4成員函數的實現方式類的成員函數

類的成員函數的定義方式有兩種:

第一種方式是在類中進行函數原型說明,而函數體則在類外進行定義。

采用這種方式定義類函數時,必須用作用域符“::”表明該函數所屬的類。

類的成員函數的定義方式有兩種:

返回類型類名::函數名(參數列表){//函數體}

【例3-5】定義時鐘類。#include"stdafx.h"#include"iostream"usingnamespacestd;classClock{private:inthour,minute,second;public:voidsetTime(intnewH,intnewM,intnewS);//函數原型說明voidshowTime();//函數原型說明};

【例3-5】定義時鐘類。

voidClock::setTime(intnewH,intnewM,intnewS)//定義成員函數{ hour=newH; minute=newM;second=newS}

voidClock::setTime(int

說明:

(1)在定義成員函數時,對函數所帶的參數,既要說明其類型,也要指出參數名;

(2)在定義成員函數時,其返回值必須與函數原型聲明中的返回類型相同。

第二種方式是在類內直接進行定義。這種方式一般用在代碼比較少的成員函數。

說明:

3.2.5成員函數設置為內聯函數

一般的函數使用過程中,需要進行函數調用,由于在調用函數時,需要保存現場和返回地址、進行參數傳遞,再轉到子函數的代碼起始地址去執(zhí)行。子函數執(zhí)行完后,又要取出以前保存的返回地址和現場狀態(tài),再繼續(xù)執(zhí)行。

內聯函數與一般函數的區(qū)別在于它不是在調用時發(fā)生控制轉移,而是在編譯時將函數體嵌入到每一個調用處。這樣就節(jié)省了參數傳遞、控制轉移等開銷。

3.2.5成員函數設置為內聯函數內聯函數的定義格式為:

inline返回值類型

函數名(形參列表){//函數體}

說明:(1)內聯函數體內不能含有循環(huán)語句和switch語句;(2)內聯函數的定義必須出現在第一次被調用之前;(3)對內聯函數不能進行異常接口聲明。內聯函數的定義格式為:

內聯函數實際上是一種以空間換時間的方案,其缺點是加大了空間方面的開銷。它通常用在結構簡單、語句少、使用多的情況下。C++默認在類內給出函數體定義的成員函數為內聯函數。內聯函數實際上是一種以空間換時間的方案,其缺【例3-6】內聯函數應用舉例,計算正方形的面積及周長。classSquare{private: doublelength;public: Square(doublex); voidarea()//函數體在類內定義,默認為內聯函數 { cout<<"正方形的面積為:"<<length*length<<endl; } inlinevoidPerimeter();//內聯函數聲明

};Square::Square(doublex){ length=x;}【例3-6】內聯函數應用舉例,計算正方形的面積及周長。

inlinevoidSquare::Perimeter()//內聯函數定義{ cout<<"正方形的周長為:"<<4*length<<endl;}voidmain(){Squaress(2.0);ss.area();ss.Perimeter();}inlinevoidSquare::Perimeter說明:

(1)內聯函數代碼不宜過長,一般是小于10行代碼的小程序,并且不能含有復雜的分支(switch)和循環(huán)語句。

(2)在類內定義的成員函數默認為內聯函數。

(3)在類外給出函數體定義的成員函數,若要定義為內聯函數,必須加上關鍵字inline。

(4)遞歸調用的函數不能定義為內聯函數。說明:

3.2.6成員函數重載

函數重載是指兩個以上的函數,具有相同的函數名,可以對應著多個函數的實現。每種實現對應著一個函數體,但是形參的個數或者類型不同,編譯器根據實參和形參的類型及個數的最佳匹配,自動確定調用哪一個函數。

3.2.6成員函數重載函數重載是指

【例3-7】函數重載舉例。

創(chuàng)建一個類,在類中定義三個名為subtract的重載成員函數,分別實現兩個整數相減、兩個實數相減和兩個復數相減的功能structcomplex{doublereal;doubleimag;};【例3-7】函數重載舉例。classOverloaded{public: intsubtract(intx,inty); doublesubtract(doublex,doubley);//函數重載 complexsubtract(complexx,complexy);//函數重載};classOverloadedintOverloaded::subtract(intx,inty){ returnx-y;}doubleOverloaded::subtract(doublex,doubley){ returnx-y;}complexOverloaded::subtract(complexx,complexy){ complexc; c.real=x.real-y.real; c.imag=x.imag-y.imag; returnc;}intOverloaded::subtract(intintmain(){intm,n; doublex,y; complexa,b,c; Overloadedol; m=32;n=23;x=31.1; y=22.2; a.real=12.3;a.imag=10.2;b.real=23.5;b.imag=1.2; cout<<m<<"-"<<n<<"="<<ol.subtract(m,n)<<endl; cout<<x<<"-"<<y<<"="<<ol.subtract(x,y)<<endl; c=ol.subtract(a,b); cout<<"'"<<a.real<<"+"<<a.imag<<"'"<<"-"<<"'"<<b.real<<"+"<<b.imag<<"'" <<"="<<"'"<<c.real<<"+"<<c.imag<<"'"<<endl; return0;}intmain()

3.3對象的創(chuàng)建與使用

在C++中,聲明了類,只是定義了一種新的數據類型,只有當定義了類的對象后,才是生成了這種數據類型的特定實體(實例)。對象是類的實際變量,創(chuàng)建一個對象稱為實例化一個對象或創(chuàng)建一個對象實例。

3.3對象的創(chuàng)建與使用在C++中,聲

3.3.1對象的定義1、先聲明類類型,然后在使用時再定義對象定義格式與一般變量定義格式相同:

類名對象名列表;

3.3.1對象的定義1、先聲明類類型,然后在使用2、在聲明類的同時,直接定義對象classStudent{……}stud1,stud2;3、不出現類名,直接定義對象class{……}stud1,stud2;2、在聲明類的同時,直接定義對象說明:

(1)必須先定義類,然后再定義類的對象。多個對象之間用逗號分隔。

(2)聲明了一個類就是聲明了一種新的數據類型,它本身不能接收和存儲具體的值,只有定義了類的對象后,系統(tǒng)才為其對象分配存儲空間。

(3)在聲明類的同時定義的類對象是一種全局對象,它的生存期一直到整個程序運行結束。說明:

3.3.2對象成員的訪問1.通過對象名和成員運算符訪問對象的成員使用這種方式訪問對象的數據成員的一般形式為:

對象名.數據成員使用這種方式訪問對象的成員函數的一般形式為:

對象名.成員函數名(實參列表)

注意:對象只能訪問其的公有(public)成員

3.3.2對象成員的訪問1.通過對象名和成員運算符

【例3-8】建立圖書檔案類,通過鍵盤輸入每種圖書的相關信息,并按價格從低到高的順序排序輸出。classBook//Book.h{public: chartitle[20],auther[10],publish[30];//書名、作者、出版社 floatprice;//價格 voidinput(); voidoutput();};

【例3-8】建立圖書檔案類,通過鍵盤輸入每種

#include"stdafx.h"http://Book.cpp#include<iostream>usingnamespacestd;#include"Book.h"voidBook::input(){ cin>>title>>auther>>publish>>price;}voidBook::output(){ cout<<title<<""<<auther<<""<<publish<<""<<price<<endl;}

#include"stdafx.h"

intmain(){ inti,j; Bookbk[10],temp; cout<<"請輸入書名、作者、出版社和價格"<<endl; for(i=0;i<10;i++) bk[i].input(); for(i=0;i<10;i++) for(j=i+1;j<10;j++) { if(bk[i].price>bk[j].price) {temp=bk[i];bk[i]=bk[j];bk[j]=temp;} }

intmain()

cout<<"輸出結果"<<endl; cout<<"書名作者出版社價格"<<endl; for(i=0;i<10;i++) bk[i].output(); return0;}

cout<<"輸出結果"<<endl;

2.通過指向對象的指針訪問對象中的成員用這種方式訪問對象的數據成員的一般形式為:

指向對象的指針->數據成員

使用這種方式訪問對象的成員函數的一般形式為:

指向對象的指針->成員函數名(實參列表)

2.通過指向對象的指針訪問對象中的成員

【例3-9】改寫【例3-8】中的主函數,通過指向對象的指針訪問對象的數據成員和成員函數。intmain(){ inti,j; Bookbk[10],*p1,*p2,temp; cout<<"請輸入書名、作者、出版社和價格"<<endl; for(i=0;i<10;i++) { p1=&bk[i];//p1指向bk[i] p1->input();

//通過指向對象的指針訪問對象的成員函數 }

【例3-9】改寫【例3-8】中的主函數,通過

for(i=0;i<10;i++) { p1=&bk[i]; for(j=i+1;j<10;j++) { p2=&bk[j]; if(p1->price>p2->price)//通過指向對象的指針訪問對象的數據成員 { temp=*p1; *p1=*p2; *p2=temp; bk[i]=*p1; bk[j]=*p2; } } }

for(i=0;i<10;i++)

cout<<"輸出結果:"<<endl; cout<<"書名作者出版社價格"<<endl; for(i=0;i<10;i++) { p1=&bk[i]; p1->output(); }return0;}

cout<<"輸出結果:"<<endl;

3.通過對象的引用訪問對象中的成員

對象的引用變量與該對象共占同一段存儲單元,實際上它們是同一個對象,只是用不同的名字表示而已。因此完全可以通過引用變量來訪問對象中的成員。

定義一個對象的引用變量的方法為:

&引用變量名=對象名;

3.通過對象的引用訪問對象中的成員

【例3-10】通過對象的引用變量來訪問對象的數據成員和成員函數。classTime{public:inthour,minute,second;voidshowTime();};intmain(){Timet1;t1.hour=2;t1.minute=12;t1.second=34;Time&t2=t1;//定義t1對象的引用變量t2cout<<t2.hour<<endl;//通過引用變量訪問對象的數據成員cout<<t2.minute<<endl;cout<<t2.second<<endl;t2.showTime();//通過引用變量訪問對象的成員函數}

【例3-10】通過對象的引用變量來訪問對象的數據成員

3.4構造函數

構造函數(Constructor)是一種特殊的成員函數,它是用來完成在聲明對象的同時,對對象中的數據成員進行初始化。

3.4構造函數構造函數(Constr

3.4.1構造函數的定義和功能

構造函數的定義如下:

類名(形參列表);

構造函數可以在類內也可在類外定義。在類外定義構造函數的形式如下:

類名::類名(形參列表){//函數體;}

3.4.1構造函數的定義和功能構造函數的說明:(1)構造函數的名稱必須與類名相同。(2)構造函數沒有返回值類型,也不能指定為void。(3)構造函數可以有任意個任意類型的參數。(4)如果沒有顯式的定義構造函數,系統(tǒng)會自動生成一個默認的構造函數。這個構造函數不含有參數,也不對數據成員進行初始化,只負責為對象分配存儲空間。(5)如果顯式的為類定義了構造函數,系統(tǒng)將不再為類提供默認構造函數。(6)定義對象時,系統(tǒng)會自動調用構造函數。(7)構造函數可以重載。(8)構造函數一般被定義為公有訪問權限。說明:【例3-11】舉例說明構造函數的使用。classDate{private: intyear; intmonth; intday;public: Date(inty,intm,intd);//聲明構造函數 voidOutput();};【例3-11】舉例說明構造函數的使用。Date::Date(inty,intm,intd)//定義構造函數{year=y; month=m; day=d;}voidDate::Output(){cout<<year<<"/"<<month<<"/"<<day<<endl;}voidmain(){Datetoday(2012,10,10); today.Output();}Date::Date(inty,intm,intd)

3.4.2默認構造函數

如果類沒有定義構造函數,系統(tǒng)會自動生成一個默認的構造函數。這個構造函數不含有參數,也不會對數據成員進行初始化。默認構造函數的形式如下:

類名::構造函數名(){}

此時要特別注意,數據成員的值是隨機的。程序運行時容易出錯。

3.4.2默認構造函數如果類沒有

3.4.3無參構造函數classPoint{

private:

intx;

inty;

public:

Point();};Point::Point(){

x=1;

y=2;}

3.4.3無參構造函數classPoint

3.4.4構造函數的重載

一個類可以定義多個構造函數,這些構造函數具有相同的名字,但參數的個數或參數的類型存在差別,這稱為構造函數的重載。

3.4.4構造函數的重載一個類可【例3-12】構造函數重載舉例。classDate{private: intyear; intmonth; intday;public: Date();//無參的構造函數 Date(inty,intm,intd);//含參的構造函數 voidOutput();};【例3-12】構造函數重載舉例。Date::Date(){year=2012;

month=10; day=11;}Date::Date(inty,intm,intd){year=y; month=m; day=d;}Date::Date()voidDate::Output(){cout<<year<<"/"<<month<<"/"<<day<<endl;}voidmain(){ Datetoday(2012,10,10); Datetomorrow; today.Output(); tomorrow.Output();}voidDate::Output()

3.4.5帶默認參數的構造函數

帶默認參數的構造函數的原型定義形式如下:

類名(函數名)(參數1=默認值,參數2=默認值,…);

所謂的默認參數即為該參數設置一個默認的值,可以為全部或者部分參數設置默認值。

3.4.5帶默認參數的構造函數帶默認【例3-13】帶默認參數的構造函數應用舉例。classDate{private: intyear; intmonth; intday;public: Date(inty=2012,intm=1,intd=1);//定義帶默認參數的構造函數 voidOutput();};【例3-13】帶默認參數的構造函數應用舉例。Date::Date(inty,intm,intd){ year=y;month=m; day=d;}voidDate::Output(){cout<<year<<"/"<<month<<"/"<<day<<endl;}voidmain(){Datetoday(2012,10,10);//使用給定值初始化對象 Datelongago;//使用默認值初始化對象 today.Output(); longago.Output();}Date::Date(inty,intm,intd)說明:(1)默認參數只能在原型聲明中指定,不能在構造函數的定義中指定。(2)在構造函數原型聲明中,所有給默認值的參數都必須在不給默認值的參數的右面。(3)在對象定義時,若省略構造函數的某個參數的值,則其右面所有參數的值都必須省略,而采用默認值。(4)構造函數帶有默認參數時,在定義對象時要注意避免二義性。例如:Date(inty=2012,intm=1,intd=1);Date();說明:

3.4.6構造函數與初始化列表

構造函數也可以采用構造初始化列表的方式對數據成員進行初始化。例如,可以把【例3-12】中的構造函數Date(inty,intm,intd)的定義改寫為:Date::Date(inty,intm,intd):year(y),month(m),day(d){}

它與【例3-12】的定義等價

3.4.6構造函數與初始化列表構造函數也

3.5析構函數

析構函數(Destructor)與構造函數相反,當對象的生命期結束(刪除對象)時,就會自動執(zhí)行析構函數。

3.5析構函數析構函數(Destr系統(tǒng)執(zhí)行析構函數的四種情況:(1)在一個函數中定義了一個對象,當這個函數被調用結束時,該對象應該釋放,在對象釋放前會自動執(zhí)行析構函數。(2)具有static屬性的對象(靜態(tài)對象,將在第四章介紹)在函數調用結束時該對象并不釋放,因此也不調用析構函數。只在main函數結束或調用exit函數結束程序時,其生命期將結束,這時才調用析構函數。(3)全局對象,在main函數結束時,其生命期將結束,這時才調用其的析構函數。(4)用new運算符動態(tài)地建立了一個對象,當用delete運算符釋放該對象時,調用該對象的析構函數。系統(tǒng)執(zhí)行析構函數的四種情況:析構函數的定義格式為:

~類名();

說明:(1)析構函數名是由“~”加類名組成。(2)析構函數沒有參數、沒有返回值,而且不能重載。(3)一個類有且僅有一個析構函數,且應為public。(4)在對象的生命期結束前,由系統(tǒng)自動調用析構函數。(5)如果沒有定義析構函數,系統(tǒng)會自動生成一個默認的析構函數,這個析構函數不做任何事情。析構函數的定義格式為:【例3-14】析構函數應用舉例#include<string>#include"iostream"usingnamespacestd;classStudent{private: stringname; intnumber;public: Student(stringna,intnu); ~Student();//析構函數原型聲明 voidOutput();};【例3-14】析構函數應用舉例Student::Student(stringna,intnu){ name=na; number=nu;}Student::~Student()//析構函數定義{ cout<<"destruct..."<<endl;}

Student::Student(stringna,invoidStudent::Output(){cout<<"姓名"<<":"<<name<<endl; cout<<"學號"<<":"<<number<<endl;}intmain(){StudentS1("Tom",100021); S1.Output(); return0;}voidStudent::Output()C++面向對象程序設計第三章類與對象課件

3.6構造函數和析構函數的調用順序

一般情況下,調用析構函數的次序正好與調用構造函數的次序相反,也就是最先被調用的構造函數,其對應的析構函數最后被調用,而最后被調用的構造函數,其對應的析構函數最先被調用。

3.6構造函數和析構函數的調用順序一般

(1)全局對象(在函數之外定義)的構造函數在文件中的所有函數(包括main函數)執(zhí)行之前調用。但如果一個程序中有多個文件,而不同的文件中都定義了全局對象,則這些對象的構造函數的執(zhí)行順序是不確定的。當main函數執(zhí)行完畢或調用exit函數時(此時程序終止),調用其的析構函數。

(2)局部對象(在函數中定義的對象)在建立對象時調用其構造函數。如果函數被多次調用,則在每次建立對象時都要調用構造函數。在函數調用結束、對象釋放前先調用析構函數。

(3)如果在函數中定義了靜態(tài)(static)局部對象,則只在程序第一次調用此函數建立對象時調用構造函數一次,在調用結束時對象并不被釋放,因此也不調用析構函數,只在main函數結束或調用exit函數結束程序時,才調用析構函數。

(1)全局對象(在函數之外定義)的構造函數在

[例2-7]構造函數與析構函數的執(zhí)行順序——Point類的多個對象的創(chuàng)建classPoint{ //point.hprivate: intx,y;public: Point(inta,intb); ~Point();};

[例2-7]構造函數與析構函數的執(zhí)行順序——Poin#include"stdafx.h"#include"iostream" //point.cppusingnamespacestd;#include"point.h"intmain(){ Pointp1(1,2),p2(3,5); return0;}#include"stdafx.h"Point::Point(inta,intb) //定義構造函數{ cout<<"constructor......."<<endl; x=a; y=b; cout<<'('<<x<<','<<y<<')'<<endl;}Point::~Point() //定義析構函數{ cout<<"destructor........"<<endl; cout<<'('<<x<<','<<y<<')'<<endl;}Point::Point(inta,intb) 說明:調用構造函數的順序與主函數main中創(chuàng)建對象的順序一致,先創(chuàng)建對象p1,然后再創(chuàng)建對象p2;調用析構函數的順序與創(chuàng)建對象的順序相反,先析構對象p2,然后再析構對象p1。(4)除了在顯式撤銷對象時,系統(tǒng)會自動調用析構函數,在下列情況下,析構函數也會被調用:①如果一個對象被定義在一個函數體內,則當這個函數結束時,該對象的析構函數會被自動調用說明:調用構造函數的順序與主函數main中創(chuàng)建對象的順序一

【例3-15】構造函數與析構函數執(zhí)行順序舉例classTime{private: inthour; intminute; intsecond;public: Time(inth,intm,ints); ~Time();};

【例3-15】構造函數與析構函數執(zhí)行順序舉例

Time::Time(inth,intm,ints){hour=h; minute=m; second=s; cout<<"TimeConstructor"<<hour<<":"<<minute<<":"<<second<<endl;}Time::~Time(){ cout<<"TimeDestructor"<<hour<<":"<<minute<<":"<<second<<endl;}

Time::Time(inth,intm,in

classDate{private: intyear; intmonth; intday;public:Date(inty,intm,intd);//聲明構造函數 ~Date();//聲明析構函數}yesteday(2012,10,10);//定義全局對象

classDate

Date::Date(inty,intm,intd)//定義構造函數{ year=y; month=m; day=d; Timetime(11,11,11);//在類Date定義的構造函數中定義類Time的對象(局部) staticTimetime1(12,12,12);//在類Date定義的構造函數中定義類Time的靜態(tài)對象(局部)

cout<<"DateConstructor"<<year<<":"<<month<<":"<<day<<endl;}

Date::Date(inty,intm,in

Date::~Date(){ cout<<"DateDestructor"<<year<<":"<<month<<":"<<day<<endl;}

voidmain(){cout<<"entermain"<<endl;Datetoday(2012,10,11);cout<<"exitmain"<<endl;}

Date::~Date()

3.7對象數組與對象指針

對象數組的元素是對象,它不僅具有數據成員,而且也具有成員函數。

定義對象數組、使用對象數組的方法與基本數據類型相似。

在執(zhí)行對象數組說明語句時,系統(tǒng)不僅為對象數組分配內存空間,以存放數組中的每個對象,而且還會自動調用匹配的構造函數完成數組內每個對象的初始化工作。

3.7.1對象數組

3.7對象數組與對象指針對象數組的

聲明對象數組的格式為:

類名

數組名[下標表達式];

在使用對象數組時,也只能引用單個數組元素,并且通過對象數組元素只能訪問其的公有成員。訪問對象數組元素的數據成員的格式為:

數組名[下標].數據成員;

訪問對象數組元素的成員函數的格式為:

數組名[下標].成員函數(實參列表);

聲明對象數組的格式為:

【例3-16】對象數組使用舉例。classBox{public:Box(inth=10,intw=12,intlen=15);//聲明有默認參數的構造函數intvolume();private:intheight;intwidth;intlength;};

【例3-16】對象數組使用舉例。

Box::Box(inth,intw,intlen):height(h),width(w),length(len){}

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

Box::Box(inth,intw,int

intmain(){Boxa[3]={//定義對象數組Box(),//調用構造函數Box,用默認參數初始化第1個元素的數據成員Box(15,18,20),//調用構造函數Box,提供第2個元素的實參Box(16,20,26)//調用構造函數Box,提供第3個元素的實參};cout<<"volumeofa[0]is"<<a[0].volume()<<endl;cout<<"volumeofa[1]is"<<a[1].volume()<<endl;cout<<"volumeofa[2]is"<<a[2].volume()<<endl;}

intmain()

聲明對象指針的格式為:

類名*對象指針名;

用對象指針訪問對象數據成員的格式為:

對象指針名->數據成員;

用對象指針訪問對象成員函數的格式為:

對象指針名->成員函數(實參列表);

同一般變量的指針一樣,對象指針在使用之前必須先進行初始化??梢宰屗赶蛞粋€已定義的對象,也可以用new運算符動態(tài)建立堆對象。

3.7.2對象指針聲明對象指針的格式為:

3.7.2對【例3-17】對象指針應用舉例。#include"stdafx.h"#include<iostream>usingnamespacestd;classSquare{private: doublelength;public: Square(doublelen); voidOutpout();};Square::Square(doublelen):length(len){}

【例3-17】對象指針應用舉例。

voidSquare::Outpout(){ cout<<"SquareArea:"<<length*length<<endl;}

intmain(){ Squares(2.5),*s1; s1=&s; s1->Outpout(); Square*s2=newSquare(3.5); s2->Outpout(); deletes2; return0;}

voidSquare::Outpout()

也可以通過對象指針來訪問對象數組,這時對象指針指向對象數組的首地址?!纠?-18】改寫【例3-16】的主函數,通過對象指針引用Box類的對象數組。intmain(){Boxa[3]={//定義對象數組|Box(),//調用構造函數Box,用默認參數初始化第1個元素的數據成員Box(15,18,20),//調用構造函數Box,提供第2個元素的實參Box(16,20,26)//調用構造函數Box,提供第3個元素的實參};Box*p=a;for(inti=0;i<3;i++,p++){ cout<<"volumeofa["<<i<<"]is"<<p->volume()<<endl;}}

也可以通過對象指針來訪問對象數組,這時對象指針指向對

this指針是一個隱含于每一個成員函數中的特殊指針。它是一個指向正操作該成員函數的對象。當對一個對象調用成員函數時,編譯程序先將對象的地址賦給this指針,然后調用成員函數。每次成員函數存取數據成員時,C++編譯器將根據this指針所指向的對象來確定應該引用哪一個對象的數據成員。

通常this指針在系統(tǒng)中是隱含存在的,也可以把它顯式表示出來。

3.7.3this指針this指針是一個隱含于每一個成員函數中【例3-19】this指針應用舉例。#include<iostream>usingnamespacestd;classA{public:intget(){returni;}voidset(intx){this->i=x;cout<<"this指針保存的內存地址為:"<<this<<endl;}private:inti;};【例3-19】this指針應用舉例。intmain(){Aa;a.set(9);cout<<"對象a所在的內存地址為:"<<&a<<endl;cout<<"對象a所保存的值為:"<<a.get()<<endl;cout<<endl;Ab;b.set(999);cout<<"對象b所在的內存地址為:"<<&b<<endl;cout<<"對象b所保存的值為:"<<b.get()<<endl;return0;}intmain()C++面向對象程序設計第三章類與對象課件

3.8向函數傳遞對象C++語言中,函數的參數和返回值的傳遞方式有三種:值傳遞、指針傳遞和引用傳遞。其方法與傳遞其它類型的數據一樣。

3.8向函數傳遞對象C++語言中

把作為實參的對象的值復制給形參創(chuàng)建的局部對象,這種傳遞是單向的,只從實參到形參。因此,函數對形參值做的改變不會影響到實參。

3.8.1使用對象作為函數參數把作為實參的對象的值復制給形參創(chuàng)建的局部對象,這種傳【例3-20】對象作為函數參數應用舉例。#include"stdafx.h"#include<iostream>usingnamespacestd;classSquare{private: doublelength;public: Square(doublelen); voidAdd(Squares); voidOutpout();};【例3-20】對象作為函數參數應用舉例。Square::Square(doublelen):length(len){}voidSquare::Add(Squares){ s.length=s.length+1.0;//給形參對象的length數據成員加1}voidSquare::Outpout(){ cout<<"SquareArea:"<<length*length<<endl;}Square::Square(doublelen):leintmain(){ Squares(2.5); cout<<"addbefore"<<endl; s.Outpout(); s.Add(s); cout<<"addafter"<<endl; s.Outpout(); return0;}intmain()C++面向對象程序設計第三章類與對象課件

對象指針作為參數傳遞的是地址。也就是說實參向形參傳遞的是實參所指向對象的地址。也就是實參對象指針變量和形參對象指針變量指向同一內存地址,因而作為形參的對象,其值的改變,也就是改變了實參對象的值,所以指針傳遞是一種雙向傳遞。

3.8.2使用對象指針作為函數參數對象指針作為參數傳遞的是地址。也就是說實參向形參傳遞

【例3-21】修改【例3-30】,驗證對象指針作為函數參數是屬于雙向傳遞。classSquare{private: doublelength;public: Square(doublelen); voidAdd(Square*s);voidOutpout();};【例3-21】修改【例3-30】,驗證對象指針作為函數Square::Square(doublelen):length(len){}voidSquare::Add(Square*s){ s->length=s->length+1.0;//給形參對象的length數據成員加1}voidSquare::Outpout(){ cout<<"SquareArea:"<<length*length<<endl;}Square::Square(doublelen):leintmain(){ Squares(2.5); cout<<"addbefore"<<endl; s.Outpout(); s.Add(&s); cout<<"addafter"<<endl; s.Outpout(); return0;}intmain()C++面向對象程序設計第三章類與對象課件

采用了引用方式進行參數傳遞,形參對象就相當于是實參對象的“別名”,對形參的操作其實就是對實參的操作。

使用對象引用作為函數參數不但有指針作為參數的優(yōu)點,而且比指針作為參數更簡單、更直接。

3.8.3使用對象引用作為函數參數采用了引用方式進行參數傳遞,形參對象就相當于【例3-22】修改【例3-21】,用對象引用進行參數傳遞。#include"stdafx.h"#include<iostream>usingnamespacestd;classSquare{private: doublelength;public: Square(doublelen); voidAdd(Square&s); voidOutpout();};【例3-22】修改【例3-21】,用對象引用進行參數傳遞。Square::Square(doublelen):length(len){}voidSquare::Add(Square&s){ s.length=s.length+1.0;//給形參對象的length數據成員加1}voidSquare::Outpout(){ cout<<"SquareArea:"<<length*length<<endl;}

Square::Square(doublelen):le

intmain(){ Squares(2.5); cout<<"addbefore"<<endl; s.Outpout();s.Add(s); cout<<"addafter"<<endl; s.Outpout(); return0;}

使用引用時,應該注意遵循如下規(guī)則:

(1)引用被創(chuàng)建的同時必須被初始化(指針則可以在任何時候被初始化)。

(2)不能有NULL引用,引用必須與合法的存儲單元關聯(指針則可以是NULL)。

(3)一旦引用被初始化,就不能改變引用的關系(指針則可以隨時改變所指的對象)。

(1)值傳遞是單向的,形參的改變并不引起實參的改變。指針和引用傳遞是雙向的,可以將改變由形參“傳給”實參。(2)引用是C++中的概念。intm;int&n=m;n相當m的別名或者綽號,對n的任何操作就是對m的操作。所以n既不是m的拷貝,也不是指向m的指針,其實n就是m它自己。實際上“引用”可以做的任何事情“指針”也都能夠做。

3.8.4三種傳遞方式比較(1)值傳遞是單向的,形參的改變并不引起實參的改變。指針和引

(3)指針能夠毫無約束地操作內存中的任何東西。指針雖然功能強大,但是用起來十分危險,所以如果的確只需要借用一下某個對象的“別名”,那么就用“引用”,而不要用“指針”,以免發(fā)生意外。

(4)使用引用作為函數參數與使用指針作為函數參數相比較,前者更容易使用、更清晰,而且當參數傳遞的數據較大時,引用傳遞參數的效率高和所占存儲空間更小。

(3)指針能夠毫無約束地操作內存中的任何東西。指針雖然【例3-23】三種傳遞方式比較舉例。#include"stdafx.h"#include<iostream>usingnamespacestd;

//值傳遞voidchange1(intn){cout<<"\n"<<"值傳遞--函數操作地址"<<&n;

//顯示的是拷貝的地址而不是源地址n++;}

【例3-23】三種傳遞方式比較舉例。

//引用傳遞voidchange2(int&n){cout<<"\n"<<"引用傳遞--函數操作地址"<<&n; n++;}

//指針傳遞voidchange3(int*n){cout<<"\n"<<"指針傳遞--函數操作地址"<<&*n; *n=*n+1;}

//引用傳遞

intmain(){ intn=10;cout<<"實參的地址"<<&n; change1(n);cout<<"\n"<<"afterchange1()n="<<n; change2(n);cout<<"\n"<<"afterchange2()n="<<n; change3(&n); cout<<"\n"<<"afterchange3()n="<<n<<"\n"; return0;}

intmain()

代碼效率上看。以對象傳遞方式的效率相對低一些。它需要創(chuàng)建新的對象來接受實參傳來的值。用對象指針傳遞的方式效率會略高一些。而當為對象引用形式時效率就更高,因為它就是實參本身。

1代碼效率上看。以對象傳遞方式的效率相對低一些。它需要

溫馨提示

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

評論

0/150

提交評論