譚浩強版《C++程序設計》第9章n.ppt
《譚浩強版《C++程序設計》第9章n.ppt》由會員分享,可在線閱讀,更多相關《譚浩強版《C++程序設計》第9章n.ppt(89頁珍藏版)》請在裝配圖網(wǎng)上搜索。
1、第9章 關于類和對象的進一步討論,9.1 構造函數(shù) 9.2 析構函數(shù) 9.3 調(diào)用構造函數(shù)和析構函數(shù)的順序 9.4 對象數(shù)組 9.5 對象指針 9.6 共用數(shù)據(jù)的保護 9.7 對象的動態(tài)建立和釋放 9.8 對象的賦值和復制 9.9 靜態(tài)成員 9.10 友元 9.11 類模板,在建立一個對象時,作某些初始化的工作如對數(shù)據(jù)成員賦初值。即在創(chuàng)建對象(分配內(nèi)存時)進行數(shù)據(jù)成員的初始化,因為對象是實實在在的對象,不能無具體屬性值。 注意: 類的數(shù)據(jù)成員是不能在聲明類時初始化的。,9.1 構造函數(shù)作用:創(chuàng)建對象(分配內(nèi)存時)時進行數(shù)據(jù)成員的初始化9.1.1 對象的初始化,如果一個類中所有的成員都是公用的,
2、則可以在定義對象時對數(shù)據(jù)成員進行初始化。如 class Time public: //聲明為公用成員 hour; minute; sec; ; Time t1=14,56,30; //將t1初始化為14:56:30 但是,一般數(shù)據(jù)成員是私有的,或者類中有private或protected的成員,就不能用這種方法初始化。 如何實現(xiàn)?,C++提供了構造函數(shù)(constructor)來處理對象的初始化。 構造函數(shù)是特殊的成員函數(shù),與其他成員函數(shù)不同,不需要用戶來調(diào)用它,而是在建立對象時自動執(zhí)行。 構造函數(shù)的名字必須與類名同名,而不能由用戶任意命名,以便編譯系統(tǒng)能識別它并把
3、它作為構造函數(shù)處理。 它不具有任何類型,不返回任何值。 構造函數(shù)的功能是由用戶定義的,用戶根據(jù)初始化的要求設計函數(shù)體和函數(shù)參數(shù)。,9.1.2 構造函數(shù)的作用,例9.1 在例8.3基礎上定義構造成員函數(shù)。 #include using namespace std; class Time public: Time( ) //定義構造成員函數(shù),函數(shù)名與類名相同 hour=0; //利用構造函數(shù)對對象中的數(shù)據(jù)成員賦初值 minute=0; sec=0; void set_time( ); //函數(shù)聲明 void show_time( ); //函數(shù)聲明 private: int
4、 hour; //私有數(shù)據(jù)成員 int minute; int sec; ;,void Timeset_time( ) //定義成員函數(shù),向數(shù)據(jù)成員賦值 cinhour; cinminute; cinsec; void Timeshow_time( ) //定義成員函數(shù),輸出數(shù)據(jù)成員的值 cout< 5、數(shù)據(jù)成員的值 Time t2; //建立對象t2,同時調(diào)用構造函數(shù)t2.Time( ) t2.show_time( ); //顯示t2的數(shù)據(jù)成員的值 return 0; ,程序運行的情況為: 10 25 54 (從鍵盤輸入新值賦給t1的數(shù)據(jù)成員) 10:25:54 (輸出t1的時、分、秒值) 0:0:0 (輸出t2的時、分、秒值) 也可以在類外定義構造函數(shù): TimeTime( ) //要加上類名Time和域限定 符“” hour=0; minute=0; sec=0; ,有關構造函數(shù)的使用,有以下說明: (1) 在類對象進入其作用域時調(diào)用構造函數(shù) 6、。 (2) 構造函數(shù)沒有返回值,因此也不需要在定義構造函數(shù)時聲明類型,這是它和一般函數(shù)的一個重要的不同之點。 (3) 構造函數(shù)不需用戶調(diào)用,也不能被用戶調(diào)用。 (4) 如果用戶自己沒有定義構造函數(shù),則C++系統(tǒng)會自動生成一個構造函數(shù),只是這個構造函數(shù)的函數(shù)體是空的,也沒有參數(shù),不執(zhí)行初始化操作。,不帶參數(shù)構造函數(shù),這種方式使該類的每一個對象都得到同一組初值。 帶參數(shù)的構造函數(shù),用戶希望對不同的對象賦予不同的初值。 構造函數(shù)首部的一般格式: 構造函數(shù)名(類型 1 形參1,類型2 形參2,) 實參是在定義對象時給出的。 定義對象的一般格式為 : 類名 對象名(實參1,實參2,);,9.1.3 帶參 7、數(shù)的構造函數(shù),例9.2 有兩個長方柱,其長、寬、高分別為: (1)12,20,25;(2)10,14,20。求它們的體積。編一個基于對象的程序,在類中用帶參數(shù)的構造函數(shù)。 #include using namespace std; class Box public: Box(int,int,int); //聲明帶參數(shù)的構造函數(shù) int volume( ); //聲明計算體積的函數(shù) private: int height; int width; int length; ; BoxBox(int h,int w,int len) //在類外定義帶參數(shù)的構造函數(shù) height=h; width 8、=w; length=len; ,int Boxvolume( ) //定義計算體積的函數(shù) return(height*width*length); int main( ) Box box1(12,25,30); //建立對象box1,并指定box1長、寬、高的值 cout< 9、程序運行結(jié)果如下: The volume of box1 is 9000 The volume of box2 is 9450 注意: 帶參數(shù)的構造函數(shù)中的形參,其對應的實參在定義對象時給定。,C++還提供另一種初始化數(shù)據(jù)成員的方法參數(shù)初始化表來實現(xiàn)對數(shù)據(jù)成員的初始化。 這種方法不在函數(shù)體內(nèi)對數(shù)據(jù)成員初始化,而是在函數(shù)首部實現(xiàn)。例如例9.2中定義構造函數(shù)可以改用以下形式: BoxBox(int h,int w,int len):height(h),width(w),length(len) 這種寫法方便、簡練,尤其當需要初始化的數(shù)據(jù)成員較多時更顯其優(yōu)越性。甚至可以直接在類體中(而不是在類外)定義 10、構造函數(shù)。,9.1.4 用參數(shù)初始化表對數(shù)據(jù)成員初始化,在一個類中可以定義多個構造函數(shù),以便對類對象提供不同的初始化的方法,供用戶選用。 這些構造函數(shù)具有相同的名字,而參數(shù)的個數(shù)或參數(shù)的類型不相同。這稱為構造函數(shù)的重載。 在第4章第4.6節(jié)中所介紹的函數(shù)重載的知識也適用于構造函數(shù)。 通過下面的例子可以了解怎樣應用構造函數(shù)的重載。,9.1.5 構造函數(shù)的重載,例9.3 在例9.2的基礎上,定義兩個構造函數(shù),其中一個無參數(shù),一個有參數(shù)。 #include using namespace std; class Box public: Box( ); //聲明一個無參的構造函數(shù) Box 11、(int h,int w,int len):height(h),width(w),length(len) //聲明一個有參的構造函數(shù),用參數(shù)的初始化表對數(shù)據(jù)成員初始化 int volume( ); private: int height; int width; int length; ; BoxBox( ) //定義一個無參的構造函數(shù) height=10; width=10; length=10; ,int Boxvolume( ) return(height*width*length); int main( ) Box box1; //建立對象box1,不指定 12、實參 cout< 13、選用的是無參構造函數(shù),應注意正確書寫定義對象的語句。 (3) 盡管在一個類中可以包含多個構造函數(shù),但是對于每一個對象來說,建立對象時只執(zhí)行其中一個構造函數(shù),并非每個構造函數(shù)都被執(zhí)行。,構造函數(shù)中參數(shù)的值既可以通過實參傳遞,也可以指定為某些默認值,即如果用戶不指定實參值,編譯系統(tǒng)就使形參取默認值。 例9.4 將例9.3程序中的構造函數(shù)改用含默認值的參數(shù),長、寬、高的默認值均為10。 在例9.3程序的基礎上改寫如下:,9.1.6 使用默認參數(shù)的構造函數(shù),#include using namespace std; class Box public: Box(int h=10,int w=10,int 14、 len=10); //在聲明構造函數(shù)時指定默認參數(shù) int volume( ); private: int height; int width; int length; ; BoxBox(int h,int w,int len) //在定義函數(shù)時可以不指定默認參數(shù) height=h; width=w; length=len; ,int Boxvolume( ) return(height*width*length); int main( ) Box box1; //沒有給實參 cout< 15、Box box2(15); //只給定一個實參 cout< 16、名的前面加一個“”符號。在C++中“”是位取反運算符,從這點也可以想到: 析構函數(shù)是與構造函數(shù)作用相反的函數(shù)。 當對象的生命期結(jié)束時,會自動執(zhí)行析構函數(shù)。 如果在一個函數(shù)中定義了一個對象(它是自動局部對象),當這個函數(shù)被調(diào)用結(jié)束時,對象應該釋放,在對象釋放前自動執(zhí)行析構函數(shù)。,9.2 析構函數(shù),static局部對象,只在main函數(shù)結(jié)束或調(diào)用exit函數(shù)結(jié)束程序時,才調(diào)用static局部對象的析構函數(shù)。全局對象,則在程序的流程離開其作用域時(如main函數(shù)結(jié)束或調(diào)用exit函數(shù)) 時,調(diào)用該全局對象的析構函數(shù)。 如果用new運算符動態(tài)地建立了一個對象,當用delete運算符釋放該對象時,先調(diào)用 17、該對象的析構函數(shù)。 析構函數(shù)的作用:并不是刪除對象,而是在撤銷對象占用的內(nèi)存之前完成一些清理工作,使這部分內(nèi)存可以被程序分配給新對象使用。 程序設計者事先設計好析構函數(shù),只要對象的生命期結(jié)束,程序就自動執(zhí)行析構函數(shù)來完成這些工作。,析構函數(shù)不返回任何值,沒有函數(shù)類型,也沒有函數(shù)參數(shù)。因此它不能被重載。一個類可以有多個構造函數(shù),但只能有一個析構函數(shù)。 析構函數(shù)的作用并不僅限于釋放資源方面,它還可以輸出有關的信息。 一般情況下,類的設計者應當在聲明類的同時定義析構函數(shù),以指定如何完成“清理”的工作。 如果用戶沒有定義析構函數(shù),C++編譯系統(tǒng)會自動生成一個析構函數(shù),但它只是徒有析構函數(shù)的名稱和形式, 18、實際上什么操作都不進行。想讓析構函數(shù)完成任何工作,都必須在定義的析構函數(shù)中指定。,例9.5 包含構造函數(shù)和析構函數(shù)的C++程序。 #include #include using namespace std; class Student //聲明Student類 public: student(int n,string nam,char s ) //定義構造函數(shù) num=n; name=nam; sex=s; cout< 19、ctor called.< 20、hang_fun,m); //定義對象stud2 stud2.display( ); //輸出學生2的數(shù)據(jù) return 0; ,程序運行結(jié)果如下: Constructor called. (執(zhí)行stud1的構造函數(shù)) num: 10010 (執(zhí)行stud1的display函數(shù)) name:Wang_li sex: f Constructor called. (執(zhí)行stud2的構造函數(shù)) num: 10011 (執(zhí)行stud2的display函數(shù)) name:Zhang_fun sex:m Destructor called. (執(zhí)行stud 21、2的析構函數(shù)) Destructor called. (執(zhí)行stud1的析構函數(shù)),在使用構造函數(shù)和析構函數(shù)時,需要特別注意對它們的調(diào)用時間和調(diào)用順序。 在一般情況下,調(diào)用析構函數(shù)的次序正好與調(diào)用構造函數(shù)的次序相反: 最先被調(diào)用的構造函數(shù),其對應的(同一對象中的)析構函數(shù)最后被調(diào)用,而最后被調(diào)用的構造函數(shù),其對應的析構函數(shù)最先被調(diào)用。如圖9.1示意。,9.3 調(diào)用構造函數(shù)和析構函數(shù)的順序,圖9.1,但是,并不是在任何情況下都是按這一原則處理的。對象可以在不同的作用域中定義,可以有不同的存儲類別。這些會影響調(diào)用構造函數(shù)和析構函數(shù)的時機。 下面歸納一下什么時候調(diào)用構造函數(shù)和析構函數(shù): (1) 22、 在全局范圍中定義的對象 它的構造函數(shù)在文件中的所有函數(shù)(包括main函數(shù))執(zhí)行之前調(diào)用。當main函數(shù)執(zhí)行完畢或調(diào)用exit函數(shù)時(此時程序終止),調(diào)用析構函數(shù)。,(2) 如果定義的是局部自動對象(例如在函數(shù)中定義對象),則在建立對象時調(diào)用其構造函數(shù)。如果函數(shù)被多次調(diào)用,則在每次建立對象時都要調(diào)用構造函數(shù)。在函數(shù)調(diào)用結(jié)束、對象釋放時先調(diào)用析構函數(shù)。 (3) 如果在函數(shù)中定義靜態(tài)(static)局部對象,則只在程序第一次調(diào)用此函數(shù)建立對象時調(diào)用構造函數(shù)一次,只在main函數(shù)結(jié)束或調(diào)用exit函數(shù)結(jié)束程序時,才調(diào)用析構函數(shù)。,數(shù)組也可以由對象組成(對象數(shù)組的每一個元素都是同類的對象)。 例如一個 23、班有50個學生,每個學生的屬性包括姓名、性別、年齡、成績等。如果為每一個學生建立一個對象,需要分別取50個對象名。用程序處理很不方便。這時可以定義一個“學生類”對象數(shù)組,每一個數(shù)組元素是一個“學生類”對象。例如 Student stud50; //假設已聲明了Student類,定義stud數(shù)組,有50個元素,9.4 對象數(shù)組,在建立數(shù)組時,同樣要調(diào)用構造函數(shù)。如果有50個元素,需要調(diào)用50次構造函數(shù)。 如果構造函數(shù)有多個參數(shù),則不能用在定義數(shù)組時直接提供所有實參的方法,因為一個數(shù)組有多個元素,對每個元素要提供多個實參,如果再考慮到構造函數(shù)有默認參數(shù)的情況,很容易造成實參與形參的對應關系不清 24、晰,出現(xiàn)歧義性。,如果構造函數(shù)有多個參數(shù),在定義對象數(shù)組時應當怎樣實現(xiàn)初始化呢? 在花括號中分別寫出構造函數(shù)并指定實參。如果構造函數(shù)有3個參數(shù),分別代表學號、年齡、成績。則可以這樣定義對象數(shù)組: Student Stud3= //定義對象數(shù)組 Student(1001,18,87), //調(diào)用第1個元素的構造函數(shù),為它提供3個實參 Student(1002,19,76), //調(diào)用第2個元素的構造函數(shù),為它提供3個實參 Student(1003,18,72) //調(diào)用第3個元素的構造函數(shù),為它提供3個實參 ;,在建立對象數(shù)組時,分別調(diào)用構造函數(shù),對每個元素初始化。每 25、一個元素的實參分別用括號包起來,對應構造函數(shù)的一組形參,不會混淆。 例9.6 對象數(shù)組的使用方法。 #include using namespace std; class Box public: Box(int h=10,int w=12,int len=15): height(h),width(w),length(len) //聲明有默認參數(shù)的構造函數(shù),用參數(shù)初始化表對數(shù)據(jù)成員初始化 int volume( ); private: int height; int width;,int length; ; int Boxvolume( ) return(height*width*length) 26、; int main( ) Box a3= //定義對象數(shù)組 Box(10,12,15), //調(diào)用構造函數(shù)Box,提供第1個元素的實參 Box(15,18,20), //調(diào)用構造函數(shù)Box,提供第2個元素的實參 Box(16,20,26) //調(diào)用構造函數(shù)Box,提供第3個元素的實參 ; cout< 27、 volume of a0 is 1800 volume of a1 is 5400 volume of a2 is 8320,在建立對象時,編譯系統(tǒng)會為每一個對象分配一定的存儲空間,以存放其成員。對象空間的起始地址就是對象的指針。可以定義一個指針變量,用來存放對象的指針。如果有一個類: class Time public: int hour; int minute; int sec; void get_time( ); ;,9.5 對象指針 9.5.1 指向?qū)ο蟮闹羔?void Timeget_time( ) couthour pt所指向的對象中的hour成員,即t1.hour (*p 28、t).get_time ( ) 調(diào)用pt所指向的對象中的get_time函數(shù),即t1.get_time pt-get_time ( ) 調(diào)用pt所指向的對象中的get_time函數(shù),即t1.get_time,對象有地址,存放對象初始地址的指針變量就是指向?qū)ο蟮闹羔樧兞俊ο笾械某蓡T也有地址,存放對象成員地址的指針變量就是指向?qū)ο蟪蓡T的指針變量。,9.5.2 指向?qū)ο蟪蓡T的指針,1. 指向?qū)ο髷?shù)據(jù)成員的指針 定義指向?qū)ο髷?shù)據(jù)成員的指針變量的方法和定義指向普通變量的指針變量方法相同。例如 int *p1; //定義指向整型數(shù)據(jù)的指針變量 定義指向?qū)ο髷?shù)據(jù)成員的指針變量的一般形式為 數(shù)據(jù) 29、類型名 *指針變量名; 如果Time類的數(shù)據(jù)成員hour為公用的整型數(shù)據(jù),則可以在類外通過指向?qū)ο髷?shù)據(jù)成員的指針變量訪問對象數(shù)據(jù)成員hour。 p1= //輸出t1.hour的值,例9.7 有關對象指針的使用方法。 #include using namespace std; class Time public: Time(int,int,int); int hour; int minute; int sec; void get_time( ); //聲明公有成員函數(shù) ;,TimeTime(int h,int m,int s) hour=h; minute=m; sec=s; void 30、 Timeget_time( ) //定義公有成員函數(shù) coutget_time( ); //調(diào)用p2所指向?qū)ο?即t1)的get_time函數(shù) ,每個對象中的數(shù)據(jù)成員都分別占有存儲空間,如果對同一個類定義了n個對象,則有n組同樣大小的空間以存放n個對象中的數(shù)據(jù)成員。但是,不同對象都調(diào)用同一個函數(shù)代碼段。 那么,當不同對象的成員函數(shù)引用數(shù)據(jù)成員時,怎么能保證引用的是所指定的對象的數(shù)據(jù)成員呢?,9.5.3 this 指針,在每一個成員函數(shù)中都包含一個特殊的指針,這個指針的名字是固定的,稱為this。 它是指向本類對象的指針,它的值是當前被調(diào)用的成員函數(shù)所在的對象的起始地址。例如,當 31、調(diào)用成員函數(shù)a.volume時,編譯系統(tǒng)就把對象a的起始地址賦給this指針,于是在成員函數(shù)引用數(shù)據(jù)成員時,就按照this的指向找到對象a的數(shù)據(jù)成員。例如volume函數(shù)要計算height*width*length的值,實際上是執(zhí)行: (this-height)*(this-width)*(this-length) 由于當前this指向a,因此相當于執(zhí)行: (a.height)*(a.width)*(a.length) 這就計算出長方體a的體積。,this指針是隱式使用的,它是作為參數(shù)被傳遞給成員函數(shù)的。本來,成員函數(shù)volume的定義如下: int Boxvolume( ) return ( 32、height*width*length); C++把它處理為 int Boxvolume(Box *this) return(this-height * this-width * this-length); 即在成員函數(shù)的形參表列中增加一個this指針。在調(diào)用該成員函數(shù)時,實際上是用以下方式調(diào)用的: a.volume( 將對象a的地址傳給形參this指針。然后按this的指向去引用其他成員。,需要說明: 這些都是編譯系統(tǒng)自動實現(xiàn)的,編程序者不必人為地在形參中增加this指針,也不必將對象a的地址傳給this指針。 在需要時也可以顯式地使用this指針。例如在Box類的volume函數(shù)中 33、,下面兩種表示方法都是合法的、相互等價的。 return(height * width * length); //隱含使用this指針 return(this-height * this-width * this-length); //顯式使用this指針 可以用*this表示被調(diào)用的成員函數(shù)所在的對象,*this就是this所指向的對象,即當前的對象。例如在成員函數(shù)a.volume( )的函數(shù)體中,如果出現(xiàn)*this,它就是本對象a。上面的return語句也可寫成 return((*this).height * (*this).width * (*this).length);,注 34、意*this兩側(cè)的括號不能省略,不能寫成*this.height。 所謂“調(diào)用對象a的成員函數(shù)f”,實際上是在調(diào)用成員函數(shù)f時使this指針指向?qū)ο骯,從而訪問對象a的成員。在使用“調(diào)用對象a的成員函數(shù)f”時,應當對它的含義有正確的理解。,有時人們希望在需要用到對象時才建立對象,在不需要用該對象時就撤銷它,釋放它所占的內(nèi)存空間以供別的數(shù)據(jù)使用。這樣可提高內(nèi)存空間的利用率。 用new運算符動態(tài)建立對象,用delete運算符撤銷對象。 如果已經(jīng)定義了一個Box類,可以用下面的方法動態(tài)地建立一個對象:,9.7 對象的動態(tài)建立和釋放,new Box; 編譯系統(tǒng)開辟了一段內(nèi)存空間,并在此內(nèi)存空間中存放一 35、個Box類對象,同時調(diào)用該類的構造函數(shù),以使該對象初始化(如果已對構造函數(shù)賦予此功能的話)。但是此時用戶還無法訪問這個對象,因為這個對象既沒有對象名,用戶也不知道它的地址。這種對象稱為無名對象,它確實是存在的,但它沒有名字。 用new運算符動態(tài)地分配內(nèi)存后,將返回一個指向新對象的指針的值,即所分配的內(nèi)存空間的起始地址。用戶需要定義一個指向本類的對象的指針變量來存放該地址。如 Box *pt; //定義一個指向Box類對象的指針變量pt pt=new Box; //在pt中存放了新建對象的起始地址,在程序中就可以通過pt訪問這個新建的對象。如 coutheight; //輸出該 36、對象的height成員 coutvolume( ); //調(diào)用該對象的volume函數(shù),計算并輸出體積 C++還允許在執(zhí)行new時,對新建立的對象進行初始化。如(調(diào)帶參數(shù)的構造函數(shù)) Box *pt=new Box(12,15,18); 這種寫法是把上面兩個語句(定義指針變量和用new建立新對象)合并為一個語句,并指定初值。這樣更精煉。新對象中的height,width和length分別獲得初值12,15,18。 調(diào)用對象既可以通過對象名,也可以通過指針。用new建立的動態(tài)對象一般是不用對象名的,是通過指針訪問的,它主要應用于動態(tài)的數(shù)據(jù)結(jié)構,如鏈表。訪問鏈表中的結(jié)點,并不需要通過對象名,, 37、在執(zhí)行new運算時,如果內(nèi)存量不足,無法開辟所需的內(nèi)存空間,目前大多數(shù)C++編譯系統(tǒng)都使new返回一個0指針值。只要檢測返回值是否為0,就可判斷分配內(nèi)存是否成功。 在不再需要使用由new建立的對象時,可以用delete運算符予以釋放。如 delete pt; //釋放pt指向的內(nèi)存空間,這就撤銷了pt指向的對象。 在執(zhí)行delete運算符時,在釋放內(nèi)存空間之前,自動調(diào)用析構函數(shù),完成有關善后清理工作。,如果對一個類定義了兩個或多個對象,則這些同類的對象之間可以互相賦值,即一個對象的值可以賦給另一個同類的對象。對象的值是指對象中所有數(shù)據(jù)成員的值。 對象之間的賦值也是通過賦值運算符“=”進行 38、的。本來,賦值運算符“=”只能用來對單個的變量賦值,現(xiàn)在被擴展為兩個同類對象之間的賦值,這是通過對賦值運算符的重載實現(xiàn)的。實際這個過程是通過成員復制來完成的,即將一個對象的成員值一一復制給另一對象的對應成員。,9.8 對象的賦值和復制COPY 9.8.1 對象的賦值,對象名1 = 對象名2; 注意對象名1和對象名2必須屬于同一個類。 例如 Student stud1,stud2; //定義兩個同類的對象 stud2=stud1; //將stud1賦給stud2 通過下面的例子可以了解怎樣進行對象的賦值。 例9.9 對象的賦值。 #include using namespace st 39、d; class Box public: Box(int=10,int=10,int=10); //聲明有默認參數(shù)的構造函數(shù) int volume( ); private: int height; int width;,int length; ; BoxBox(int h,int w,int len) height=h; width=w; length=len; int Boxvolume( ) return(height*width*length); //返回體積 int main( ) Box box1(15,30,25),box2; //定義兩個對象box1和box2 40、cout< 41、同的對象。此外,有時需要將對象在某一瞬時的狀態(tài)保留下來。這就是對象的復制機制。用一個已有的對象快速地復制出多個完全相同的對象。如 Box box2(box1); 其作用是用已有的對象box1去克隆出一個新對象box2。 其一般形式為 類名 對象2(對象1); 用對象1復制出對象2。,9.8.2 對象的復制,可以看到: 它與前面介紹過的定義對象方式類似,但是括號中給出的參數(shù)不是一般的變量,而是對象。在建立對象時調(diào)用一個特殊的構造函數(shù)復制構造函數(shù)(copy constructor)。這個函數(shù)的形式是這樣的: //The copy constructor definition. BoxBox(con 42、st Box 復制構造函數(shù)也是構造函數(shù),但它只有一個參數(shù),這個參數(shù)是本類的對象(不能是其他類的對象),而且采用對象的引用的形式(一般約定加const聲明,使參數(shù)值不能改變,以免在調(diào)用此函數(shù)時因不慎而使對象值被修改)。,此復制構造函數(shù)的作用就是將實參對象的各成員值一一賦給新的對象中對應的成員。 回顧復制對象的語句 Box box2(box1); 這實際上也是建立對象的語句,建立一個新對象box2。由于在括號內(nèi)給定的實參是對象,因此編譯系統(tǒng)就調(diào)用復制構造函數(shù)(它的形參也是對象),而不會去調(diào)用其他構造函數(shù)。實參box1的地址傳遞給形參b(b是box1的引用),因此執(zhí)行復制構造函數(shù)的函數(shù)體時,將box 43、1對象中各數(shù)據(jù)成員的值賦給box2中各數(shù)據(jù)成員。 如果用戶自己未定義復制構造函數(shù),則編譯系統(tǒng)會自動提供一個默認的復制構造函數(shù),其作用只是簡單地復制類中每個數(shù)據(jù)成員。,C++還提供另一種方便用戶的復制形式,用賦值號代替括號,如 Box box2=box1; //用box1初始化box2 其一般形式為 類名 對象名1 = 對象名2; 可以在一個語句中進行多個對象的復制。如 Box box2=box1,box3=box2; 按box1來復制box2和box3??梢钥闯觯?這種形式與變量初始化語句類似,請與下面定義變量的語句作比較: int a=4,b=a; 這種形式看起來很直觀,用起來很方便。但 44、是其作用都是調(diào)用復制構造函數(shù)。,請注意對象的復制和對象的賦值在概念上和語法上的區(qū)別。對象的賦值是對一個已經(jīng)存在的對象賦值,因此必須先定義被賦值的對象,才能進行賦值。而對象的復制則是從無到有地建立一個新對象,并使它與一個已有的對象完全相同(包括對象的結(jié)構和成員的值)。 可以對例9.7程序中的主函數(shù)作一些修改: int main( ) Box box1(15,30,25); //定義box1 cout< 45、,box3 cout< 46、3種情況下需要克隆對象:, 程序中需要新建立一個對象,并用另一個同類的對象對它初始化,如前面介紹的那樣。 當函數(shù)的參數(shù)為類的對象時。在調(diào)用函數(shù)時需要將實參對象完整地傳遞給形參,也就是需要建立一個實參的拷貝,這就是按實參復制一個形參,系統(tǒng)是通過調(diào)用復制構造函數(shù)來實現(xiàn)的,這樣能保證形參具有和實參完全相同的值。如 void fun(Box b) //形參是類的對象 int main( ) Box box1(12,15,18); fun(box1); //實參是類的對象,調(diào)用函數(shù)時將復制一個新對象b return 0; , 函數(shù)的返回值是類的對象。在函數(shù)調(diào)用完畢將返回值帶回函數(shù)調(diào)用處 47、時。此時需要將函數(shù)中的對象復制一個臨時對象并傳給該函數(shù)的調(diào)用處。如 Box f( ) //函數(shù)f的類型為Box類類型 Box box1(12,15,18); return box1; //返回值是Box類的對象 int main( ) Box box2; //定義Box類的對象box2 box2=f( ); //調(diào)用f函數(shù),返回Box類的臨時對象,并將它賦值給box2 以上幾種調(diào)用復制構造函數(shù)都是由編譯系統(tǒng)自動實現(xiàn)的,不必由用戶自己去調(diào)用,讀者只要知道在這些情況下需要調(diào)用復制構造函數(shù)就可以了。,如果有n個同類的對象,那么每一個對象都分別有自己的數(shù)據(jù)成員,不同對象 48、的數(shù)據(jù)成員各自有值,互不相干。但是有時人們希望有某一個或幾個數(shù)據(jù)成員為所有對象所共有。這樣可以實現(xiàn)數(shù)據(jù)共享。 在第7章中曾介紹過全局變量,它能夠?qū)崿F(xiàn)數(shù)據(jù)共享。如果在一個程序文件中有多個函數(shù),在每一個函數(shù)中都可以改變?nèi)肿兞康闹?,全局變量的值為各函?shù)共享。但是用全局變量的安全性得不到保證,由于在各處都可以自由地修改全局變量的值,很有可能偶一失誤,全局變量的值就被修改,導致程序的失敗。因此在實際工作中很少使用全局變量。 如果想在同類的多個對象之間實現(xiàn)數(shù)據(jù)共享,也不要用全局對象,可以用靜態(tài)的數(shù)據(jù)成員。,9.9 靜態(tài)成員,靜態(tài)數(shù)據(jù)成員是一種特殊的數(shù)據(jù)成員。它以關鍵字static開頭。例如 class 49、Box public: int volume( ); private: static int height; //把height定義為靜態(tài)的數(shù)據(jù)成員 int width; int length; ; 如果希望各對象中的height的值是一樣的,就可以把它定義為靜態(tài)數(shù)據(jù)成員,這樣它就為各對象所共有,而不只屬于某個對象的成員,,9.9.1 靜態(tài)數(shù)據(jù)成員,所有對象都可以引用它。每個對象都可以引用這個靜態(tài)數(shù)據(jù)成員。靜態(tài)數(shù)據(jù)成員的值對所有對象都是一樣的。如果改變它的值,則在各對象中這個數(shù)據(jù)成員的值都同時改變了。這樣可以節(jié)約空間,提高效率。 說明: (1) 靜態(tài)數(shù)據(jù)成員不屬于某一個對象,在為對象 50、所分配的空間中不包括靜態(tài)數(shù)據(jù)成員所占的空間。靜態(tài)數(shù)據(jù)成員是在所有對象之外單獨開辟空間。只要在類中定義了靜態(tài)數(shù)據(jù)成員,即使不定義對象,也為靜態(tài)數(shù)據(jù)成員分配空間,它可以被引用。,(2) 靜態(tài)數(shù)據(jù)成員,它不隨對象的建立而分配空間,也不隨對象的撤銷而釋放。靜態(tài)數(shù)據(jù)成員是在程序編譯時被分配空間的,到程序結(jié)束時才釋放空間。 (3) 靜態(tài)數(shù)據(jù)成員可以初始化,但只能在類體外進行初始化。如 int Boxheight=10; //表示對Box類中的數(shù)據(jù)成員初始化,其一般形式為 數(shù)據(jù)類型類名靜態(tài)數(shù)據(jù)成員名=初值; 不必在初始化語句中加static。 注意: 不能用參數(shù)初始化表對靜態(tài)數(shù)據(jù)成員初始化。如在定義 51、Box類中這樣定義構造函數(shù)是錯誤的: Box(int h,int w,int len):height(h) //錯誤,height是靜態(tài)數(shù)據(jù)成員 如果未對靜態(tài)數(shù)據(jù)成員賦初值,則編譯系統(tǒng)會自動賦予初值0。 (4) 靜態(tài)數(shù)據(jù)成員既可以通過對象名引用,也可以通過類名來引用。 例9.10 引用靜態(tài)數(shù)據(jù)成員。,#include using namespace std; class Box public: Box(int,int); int volume( ); static int height; //把height定義為公用的靜態(tài)的數(shù)據(jù)成員 int width; int length; ; B 52、oxBox(int w,int len) //通過構造函數(shù)對width和length賦初值 width=w; length=len; int Boxvolume( ) return(height*width*length); int Boxheight=10; //對靜態(tài)數(shù)據(jù)成員height初始化,int main( ) Box a(15,20),b(20,30); cout< 53、類名引用靜態(tài)數(shù)據(jù)成員 cout< 54、引用。 (5) 靜態(tài)數(shù)據(jù)成員的作用:各對象之間的數(shù)據(jù)有了溝通的渠道,實現(xiàn)數(shù)據(jù)共享,因此可以不使用全局變量。全局變量破壞了封裝的原則,不符合面向?qū)ο蟪绦虻囊蟆?注意公用靜態(tài)數(shù)據(jù)成員與全局變量的不同,靜態(tài)數(shù)據(jù)成員的作用域只限于定義該類的作用域內(nèi)在此作用域內(nèi),可以通過類名和域運算符“”引用靜態(tài)數(shù)據(jù)成員,而不論類對象是否存在。,成員函數(shù)也可以定義為靜態(tài)的,在類中聲明函數(shù)的前面加static就成了靜態(tài)成員函數(shù)。如 static int volume( ); 和靜態(tài)數(shù)據(jù)成員一樣,如果要在類外調(diào)用公用的靜態(tài)成員函數(shù),要用類名和域運算符“”。如 Boxvolume( ); 實際上也允許通過對象名調(diào)用靜態(tài)成員 55、函數(shù),如 a.volume( ); 但這并不意味著此函數(shù)是屬于對象a的,而只是用a的類型而已。,9.9.2 靜態(tài)成員函數(shù),靜態(tài)成員函數(shù)的作用:不是為了對象之間的溝通,而是為了能處理靜態(tài)數(shù)據(jù)成員。 前面曾指出: 當調(diào)用一個對象的成員函數(shù)(非靜態(tài)成員函數(shù))時,系統(tǒng)會把該對象的起始地址賦給成員函數(shù)的this指針。而靜態(tài)成員函數(shù)并不屬于某一對象,它與任何對象都無關,因此靜態(tài)成員函數(shù)沒有this指針。既然它沒有指向某一對象,就無法對一個對象中的非靜態(tài)成員進行默認訪問。 靜態(tài)成員函數(shù)與非靜態(tài)成員函數(shù)的根本區(qū)別: 非靜態(tài)成員函數(shù)有this指針,而靜態(tài)成員函數(shù)沒有this指針。由此,靜態(tài)成員函數(shù)不能訪問本類中 56、的非靜態(tài)成員。,靜態(tài)成員函數(shù)可以直接引用本類中的靜態(tài)數(shù)據(jù)成員,靜態(tài)成員函數(shù)主要用來訪問靜態(tài)數(shù)據(jù)成員,而不訪問非靜態(tài)成員。假如在一個靜態(tài)成員函數(shù)中有以下語句: cout< 57、nclude using namespace std; class Student //定義Student類 public: Student(int n,int a,float s):num(n),age(a),score(s) //定義構造函數(shù) void total( ); static float average( ); //聲明靜態(tài)成員函數(shù) private: int num; int age; float score; static float sum; //靜態(tài)數(shù)據(jù)成員 static int count; //靜態(tài)數(shù)據(jù)成員 ; void Studenttotal( 58、) //定義非靜態(tài)成員函數(shù) sum+=score; //累加總分,類內(nèi)訪問靜態(tài)數(shù)據(jù)成員 count++; //累計已統(tǒng)計的人數(shù),類內(nèi)訪問靜態(tài)數(shù)據(jù)成員 ,float Studentaverage( ) //定義靜態(tài)成員函數(shù) return(sum/count); //只能訪問靜態(tài)數(shù)據(jù)成員 float Studentsum=0; //對靜態(tài)數(shù)據(jù)成員初始化 int Studentcount=0; //對靜態(tài)數(shù)據(jù)成員初始化 int main( ) Student stud3= //定義對象數(shù)組并初始化 Student(1001,18,7 59、0), Student(1002,19,78), Student(1005,20,98) ; int n; coutn; //輸入需要求前面多少名學生的平均成績 for(int i=0;i 60、f 3 students is 82.3333 說明: (1)在Student類中定義了兩個靜態(tài)數(shù)據(jù)成員sum(總分)和count(累計需要統(tǒng)計的學生人數(shù)),這是由于這兩個數(shù)據(jù)成員的值是需要進行累加的,它們并不是只屬于某一個對象元素,而是由各對象元素共享的,可以看出: 它們的值是在不斷變化的,而且無論對哪個對象元素而言,都是相同的,而且始終不釋放內(nèi)存空間。,(2)注意: total是公有的成員函數(shù),公有的成員函數(shù)可以引用本對象中的一般數(shù)據(jù)成員(非靜態(tài)數(shù)據(jù)成員),也可以引用類中的靜態(tài)數(shù)據(jù)成員。score是非靜態(tài)數(shù)據(jù)成員,sum和count是靜態(tài)數(shù)據(jù)成員。 (3) average是靜態(tài)成員函數(shù),可 61、以直接引用私有的靜態(tài)數(shù)據(jù)成員(不必加類名或?qū)ο竺?,函數(shù)返回成績的平均值。 (4) 在main函數(shù)中,引用total函數(shù)要加對象名(今用對象數(shù)組元素名),引用靜態(tài)成員函數(shù)average函數(shù)要用類名或?qū)ο竺?類的基本訪問規(guī)則:在一個類中可以有公用的(public)成員和私有的(private)成員。在類外可以訪問公用成員,只有本類中的函數(shù)可以訪問本類的私有成員。 現(xiàn)在,我們來補充介紹一個例外友元(friend)。 友元可以訪問與其有好友關系的類中的私有成員。友元包括友元函數(shù)和友元類。,9.10 友元,如果在本類以外的其他地方定義了一個函數(shù)(這個函數(shù)可以是不屬于任何類的非成員函數(shù),也可以是其他類 62、的成員函數(shù))。 在類體中用friend對其進行聲明,此函數(shù)就稱為本類的友元函數(shù)。友元函數(shù)可以訪問這個類中的私有成員,但是外部訪問。,9.10.1 友元函數(shù),1. 將普通函數(shù)聲明為友元函數(shù) 例9.12 友元函數(shù)的簡單例子。 #include using namespace std; class Time public: Time(int,int,int); friend void display(Time ,minute=m; sec=s; void display(Time //調(diào)用display函數(shù),實參t1是Time類對象 程序輸出結(jié)果如下: 10:13:56,由于聲明了disp 63、lay是Time類的friend函數(shù),所以display函數(shù)可以引用Time中的私有成員hour,minute,sec。 但注意在引用這些私有數(shù)據(jù)成員時,必須加上對象名,不能寫成 cout< 64、ass Time //定義Time類 public: Time(int,int,int); void display(Date ,int minute; int sec; ; class Date //聲明Date類 public: Date(int,int,int); friend void Timedisplay(Date ,void Timedisplay(Date ,運行時輸出: 12/25/2004 (輸出Date類對象d1中的私有數(shù)據(jù)) 10:13:56 (輸出Time類對象t1中的私有數(shù)據(jù)) 在本例中定義了兩個類Time和Date。程序第 65、3行是對Date類的聲明,因為在第7行和第16行中對display函數(shù)的聲明和定義中要用到類名Date,而對Date類的定義卻在其后面。 在一般情況下,兩個不同的類是互不相干的。在本例中,由于在Date類中聲明了Time類中的display成員函數(shù)是Date類的“朋友”,因此該函數(shù)可以引用Date類中所有的數(shù)據(jù)。請注意在本程序中調(diào)用友元函數(shù)訪問有關類的私有數(shù)據(jù)方法。,不僅可以將一個函數(shù)聲明為一個類的“朋友”,而且可以將一個類(例如B類)聲明為另一個類(例如A類)的“朋友”。這時B類就是A類的友元類。友元類B中的所有函數(shù)都是A類的友元函數(shù),可以訪問A類中的所有成員。 不講!,9.10.2 友元類,本章概念總結(jié): 構造函數(shù),析構函數(shù); 對象指針,this指針; 復制構造函數(shù) 靜態(tài)數(shù)據(jù)成員,靜態(tài)函數(shù)成員 友員,友員函數(shù),友員成員函數(shù) 掌握其作用與使用規(guī)則,
- 溫馨提示:
1: 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 川渝旅游日記成都重慶城市介紹推薦景點美食推薦
- XX國有企業(yè)黨委書記個人述責述廉報告及2025年重點工作計劃
- 世界濕地日濕地的含義及價值
- 20XX年春節(jié)節(jié)后復工安全生產(chǎn)培訓人到場心到崗
- 大唐女子圖鑒唐朝服飾之美器物之美繪畫之美生活之美
- 節(jié)后開工第一課輕松掌握各要點節(jié)后常見的八大危險
- 廈門城市旅游介紹廈門景點介紹廈門美食展示
- 節(jié)后開工第一課復工復產(chǎn)十注意節(jié)后復工十檢查
- 傳統(tǒng)文化百善孝為先孝道培訓
- 深圳城市旅游介紹景點推薦美食探索
- 節(jié)后復工安全生產(chǎn)培訓勿忘安全本心人人講安全個個會應急
- 預防性維修管理
- 常見閥門類型及特點
- 設備預防性維修
- 2.乳化液泵工理論考試試題含答案