課程設計安排市公開課獲獎課件省名師優質課賽課一等獎課件_第1頁
課程設計安排市公開課獲獎課件省名師優質課賽課一等獎課件_第2頁
課程設計安排市公開課獲獎課件省名師優質課賽課一等獎課件_第3頁
課程設計安排市公開課獲獎課件省名師優質課賽課一等獎課件_第4頁
課程設計安排市公開課獲獎課件省名師優質課賽課一等獎課件_第5頁
已閱讀5頁,還剩126頁未讀 繼續免費閱讀

下載本文檔

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

文檔簡介

課程設計安排時間:年1月15-19日下午13:00-18:00地點:綜合樓3151/131第四章類與對象

封裝(Encapsulation)是面向對象程序設計最基本特征,也就是把數據(屬性)和函數(操作)合成一個整體,這是用類與對象實現。接口(類設計)和實現(編程)分離。

本章重點:1.引入C++類(class)和對象(object)概念,建立“函數也能夠是數據類型組員”思想。2.運算符重載。 C++:CwithClasses2/131第四章類與對象4.1類與對象

4.5運算符重載

4.4引用與復制結構函數

4.2從面向過程到面向對象

4.9名字空間域和類域(選讀)

4.10面向對象程序設計和Windows編程

4.8結構4.7靜態組員

4.6友元

4.3結構函數和析構函數3/1314.1

類與對象

4.1.3對象創建與使用4.1.1C++類定義4.1.2 組員函數定義4/1314.1.1C++類定義

類引入:類是一個數據類型。描述客觀事物必須用不一樣數據類型來描述不一樣方面。如商品:

商品名稱(用字符串描述),該商品數量(用整型數描述),該商品單價(用浮點數描述),該商品總價(用浮點數描述)。這里用了屬于三種不一樣數據類型四個數據組員(datamember)來描述一個商品。5/1314.1.1C++類定義類表述:class

CGoods{

public

:

charName[21];

intAmount;

floatPrice;

floatTotal_value;}

;

//最終分號不可少,這是一條說明語句關鍵字class是數據類型說明符,指出下面說明是類。標識符CGoods是商品這個類類型名。花括號中是組成類體系列組員,關鍵字public是一個訪問限定符。6/1314.1.1C++類定義訪問限定符(accessspecifier):public(公共)說明組員能從外部(類代碼外面)進行訪問。private(私有)和protected(保護)說明組員不能從外部進行訪問。每種說明符可在類體中使用屢次。

訪問限定符作用域是從該說明符出現開始到下一個說明符之前或類體結束之前結束。假如在類體起始點無訪問說明符,系統默認定義為私有(private用關鍵字class定義類)。訪問限定符private(私有)和protected(保護)表達了類含有封裝性(Encapsulation)。7/1314.1.1C++類定義類定義:class

類名{《《private:》

組員表1;》《public:

組員表2;》《protected:

組員表3;》};//注意:全部說明都以分號結束其中“class類名”稱為類頭(classhead)。花括號中部分稱為類體(classbody),類體中定義了類組員表(classmemberlist),包含數據和函數。8/1314.1.1C++類定義組員函數(memberfunction)

:class(struct)CGoods{private:

charName[21];

int Amount;

floatPrice;

float Total_value;public://申明是必須,定義可選(放到類內部也能夠放到類外部)

voidRegisterGoods(char[],int,float);//輸入數據

void CountTotal(void);//計算商品總價值

void GetName(char[]);//讀取商品名

int GetAmount(void);//讀取商品數量

float GetPrice(void);//讀取商品單價

float GetTotal_value(void);};

//讀取商品總價值

課下查找:利用關鍵字class和struct定義類區分?9/1314.1.1C++類定義封裝:類把數據(事物屬性)和函數(事物行為——操作)封裝為一個整體。接口:通常數據組員被說明成私有,函數組員被說明成公有;從外部對數據組員進行操作,只能經過公有函數來完成,數據受到了良好保護,不易受副作用影響。公有函數集定義了類接口(interface)。組員函數能夠直接使用類定義中任一組員,能夠處理數據組員,也可調用函數組員。

10/131注意:

類是一個數據類型,定義時系統不為類分配存放空間,所以不能對類數據組員初始化。類中任何數據組員也不能使用關鍵字extern、auto或register限定其存放類型。

classCGoods;//類申明,未定義之前11/1314.1.2 組員函數定義函數定義:

通常在類定義中,組員函數僅作申明。函數定義通常在類定義之后進行,其格式以下:返回值類型

類名::函數名(參數表){……}//函數體其中運算符“::”稱為作用域解析運算符(scoperesolutionoperator),它指出該函數是屬于哪一個類組員函數。類CGoods函數定義12/131組員函數inline申明classCGoods{float GetPrice(void){//類內部定義,默認inline returnprice;}};

或者inline

floatCgoods::GetPrice(){//提議此申明方式 returnprice;}13/131組員函數const函數申明:數據組員只能夠讀取不能夠修改classCGoods{float GetPrice(void)const;};

而且floatCgoods::GetPrice()const{ returnprice;}14/131定義對象:

對象是類實例(instance)。定義一個數據類型只是告訴編譯系統該數據類型結構,并沒有預定內存。類只是一個樣板,以此樣板能夠在內存中開辟出一樣結構實例——對象。格式以下:

CGoodsCar;這個定義創建了CGoods類一個對象Car,同時為它分配了屬于它自己存放塊,用來存放數據和對這些數據實施操作組員函數(代碼)。對象只在定義它域中有效。4.1.3 對象創建與使用15/131對象存放:

圖4.1各對象完全獨立地安排內存方案

圖4.1是系統為每一個對象分配了全套內存。數據區安放組員數據,代碼區安放組員函數。注意:區分同一個類各個不一樣對象屬性是由數據組員決定,不一樣對象數據組員內容是不一樣;而行為(操作)是用函數來描述,這些操作代碼對全部對象都是一樣。數據區代碼區對象1對象2數據區代碼區對象n......數據區代碼區16/131圖4.2各對象代碼區共用方案數據區對象1數據區對象2數據區對象n......公共代碼區

圖4.2僅為每個對象分配一個數據區,代碼區(放組員函數區域)為各對象類共用。圖4.1對應是在類說明中定義函數,而圖4.2對應是在類說明外部定義函數。17/1314.1.3 對象創建與使用內聯函數:使用關鍵字inline,系統自動采取內聯擴展方法實現,每個對象都有該函數一份獨立代碼。如RegisterGoods()函數可定義為:inline

voidCGoods::RegisterGoods(charname[],

intamount,floatprice){ strcpy(Name,name);Amount=amount; Price=price;}則每個對象都有RegisterGoods()函數一份獨立代碼。18/1314.1.3 對象創建與使用對象使用規則:只要在對象名后加點號(點操作符,組員訪問運算符(memberaccessoprator)之一),再加組員數據或組員函數名就能夠了。不過這些組員必須是公有組員,只有公有組員才能在對象外面對它進行訪問。【例4.1】商品類對象應用實例【例4.1】中對象car4個數據組員全是私有,如寫:car.Name;car.Amount;car.Price;car.Total_value;是錯誤,必須用對象car所帶公有函數進行訪問。19/1314.2 從面向過程到面向對象(閱讀)結構化程序設計特點:采取是“自頂向下,逐步細化(divideandconquer,stepwiserefinement)”思想。詳細操作方法是模塊化。模塊是按功效來分,所以也稱功效塊。在C++中稱為一個函數,一個函數處理一個問題,即實現一個功效或一個操作。

在模塊化思想中已經出現了封裝概念,這個封裝是把數據封裝到模塊中,即局部變量。這是很不徹底,因為模塊是功效抽象,而數據則是含有其個性,一但發生改變,抽象功效模塊就不再適用了。可維護性差成了制約結構化程序設計瓶頸。

面向過程程序設計缺點根源在于數據與數據處理分離。

20/1314.2 從面向過程到面向對象(閱讀)結構化程序設計弱點:

當軟件規模過大,采取結構化程序設計,其開發和維護就越來越難控制。其根本原因就在于面向過程結構化程序設計方法與現實世界(包含主觀世界和客觀世界)往往都不一致,結構化程序設計思想往往極難落實到底。

對象概念:對象概念是面向對象技術關鍵所在。面向對象技術中對象就是現實世界中某個詳細物理實體在計算機邏輯中映射和表達。21/1314.2 從面向過程到面向對象(閱讀)對象類計算機世界實體抽象類別現實世界客觀世界抽象抽象實例化映射主觀世界圖4.3對象、實體與類

現實世界中實體能夠抽象出類別概念。對應于計算機世界就有一個類(class)概念。面向對象是計算機世界模擬現實世界。圖4.3表示了計算機世界與現實世界之間對應關系。22/1314.2 從面向過程到面向對象(閱讀)對象、類與消息:面向對象程序設計模擬自然界認識和處理事物方法,將數據和對數據操作方法放在一起,形成一個相對獨立整體——對象(object),同類對象還可抽象出共性,形成類(class)。一個類中數據通常只能經過本類提供方法進行處理,這些方法成為該類與外部接口。對象之間經過消息(message)進行通訊。23/1314.2 從面向過程到面向對象(閱讀)屬性行為表針旋鈕其它機械機構調整旋鈕對象24/1314.2 從面向過程到面向對象(閱讀)是一個抽象概念,用來描述某一類對象所共有、本質屬性和類行為。類類一個詳細實現,稱為實例手表一塊手表類對象描述這類對象共有、本質屬性和行為手表共有屬性(表針、旋鈕、內部結構)和行為(調整旋鈕)詳細到一只圓形或方形手表25/1314.2 從面向過程到面向對象(閱讀)我們把對象之間產生相互作用所傳遞信息稱做消息。

消息啟動發送消息接收并響應消息轉向26/1314.2 從面向過程到面向對象(閱讀)封裝性內外機械零件動作調整旋鈕讀表盤對象是一個封裝體,在其中封裝了該對象屬性和操作。經過限制對屬性和操作訪問權限,能夠將屬性“隱藏”在對象內部,對外提供一定接口,在對象之外只能經過接口對對象進行操作。C++經過建立數據類型——類來支持封裝和數據隱藏。封裝性增加了對象獨立性,從而確保了數據可靠性。一個定義完好類能夠作為獨立模塊使用。面向對象程序設計特點:27/131汽車客車貨車小轎車大客車載貨載人小,速度快大,速度慢4.2 從面向過程到面向對象(閱讀)繼承與派生以汽車為例看客觀世界描述事物方式:當定義了一個類后,又需定義一個新類,這個新類與原來類相比,只是增加或修改了部分屬性和操作,這時能夠用原來類派生出新類,新類中只需描述自己所特有屬性和操作。面向對象程序設計提供了類似機制:繼承性大大簡化了對問題描述,大大提升了程序可重用性,從而提升了程序設計、修改、擴充效率。新類稱為子類或派生類,原來類稱為基類。派生能夠一直進行下去,形成一個派生樹。28/1314.2 從面向過程到面向對象(閱讀)語文、數學、英語、政治、物理、化學、生物多態性多態性指,同一個消息被不一樣對象接收時,產生不一樣結果,即實現同一接口,不一樣方法。高中生計算平均成績大學生高數、英語、計算機、線性代數29/1314.2 從面向過程到面向對象(閱讀)繼承和多態性組合,能夠生成很多相同但又獨一無二對象。繼承性使得這些對象能夠共享許多相同特征,而多態又使同一個操作對不一樣對象產生不一樣表現形式。這么不但提升了程序設計靈活性,而且減輕了分別設計負擔。30/1314.3 結構函數和析構函數特殊組員函數,只要創建類類型對象,都要執行結構函數。功效:為數據組員分配存放空間并初始化每個對象數據組員。結構函數(constructor)4.3.1 結構函數定義與使用

4.3.2 析構函數定義31/131結構函數特征:1.函數名與類名相同。classCGoods{public:CGoods(char*name,intamount,floatprice);CGoods(intamount,floatprice)const;//error};2.結構函數無函數返回類型說明。注意是什么也不寫,也不可寫void!形式參數能夠有也能夠沒有.不能申明為const4.3.1結構函數定義與使用

32/1313.在程序運行時,當新對象被建立,該對象所屬類結構函數自動被調用,在該對象生存期中也只調用這一次。

CGoodsbook1;4.結構函數能夠重載。說明中能夠有多個結構函數,它們由不一樣參數表區分;classCGoods{public:CGoods(char*name,intamount,floatprice);CGoods(char*name,floatprice);CGoods();};思索:多個結構函數,調用時選擇哪一個?重載函數調用規則來思索。33/1314.3.1結構函數定義與使用5.結構函數能夠在類中定義,也能夠在類外定義。classCGoods{public:CGoods(char*name,intamount,floatprice){

//類內部定義

strcpy(Name,name);Amount=amount;Price=price;Total_value=price*amount;

}};或者classCGoods{public:CGoods(char*name,intamount,floatprice);//類內部申明};CGoods::CGoods(char*name,intamount,floatprice){//類外部定義strcpy(Name,name);Amount=amount;Price=price;Total_value=price*amount;}

34/1316.假如類說明中沒有給出結構函數,則C++編譯器自動創建一個默認結構函數:

類名(void){}注意:只要我們定義了一個結構函數,系統就不會自動生成默認結構函數。

只要結構函數是無參或各參數都有默認值,C++編譯器都認為是默認結構函數,而且默認結構函數只能有一個。35/1314.3.1結構函數定義與使用

CGoods結構函數:三參數:CGoods(char*name,intamount,floatprice){

strcpy(Name,name);Amount=amount;Price=price;Total_value=price*amount;

}兩參數:貨名和單價,CGoods(char*name,floatprice){

strcpy(Name,name);Price=price

;Amount=0;Total_value=0.0;}默認結構函數:CGoods(){Name[0]=‘\0’;Price=0.0;Amount=0;Total_value=0.0;}這三個結構函數同時被說明(重載)。36/1314.3.1結構函數定義與使用

實參決定調用哪個結構函數:CGoodsCar1(“夏利”,30,98000.0);調用了CGoods中第一個結構函數,等效于:CGoodsCar1=CGoods(“夏利”,30,98000.0);CGoodsCar2(“桑塔那”,164000.0);調用是第二個結構函數,參數為兩個。CGoodsCar3;定義時調用不帶參數結構函數不過定義對象時不能加括號。比如:CGoodsCar4();Car4()是不帶參數函數,它返回值是類CGoods對象。【例4.1_1】完整商品類對象應用實例37/131練習選擇一下一個抽象,確定類中需要什么數據,并提供適當結構函數。并解釋你決定。1.Book2.Date3.Student4.Vehicle5.Tree6.Computer7.Program38/131結構函數初始化式與普通函數一樣,結構函數含有名字,形參列表和函數體。不一樣:定義時能夠包含一個初始化列表(不能在申明處指出)CGoods::CGoods(char*name,intamount,floatprice):Amount(amont),Price(price){strcpy(Name,name);}注意:const,沒有默認結構函數類類型組員或引用數據組員classA{private: constinti;public:A(intvar){var=i;}//error A(intvar):i(var){}};39/131組員初始化次序:組員被定義次序決定了初始化次序.初始化列表只是僅初始化組員值,而不指定初始化次序。classX{inti;intj;public://run-timeerror:iisinitializedbeforej X(intval):j(val),i(j){}};40/1314.3.2 析構函數定義析構函數(destructor)特征:

當一個對象生命周期結束時,C++會自動調用析構函數(destructor)對該對象并進行善后工作(不嚴謹)。1.

構函數名與類名相同,但在前面加上字符‘~’,如~CGoods()。2.

析構函數無函數返回類型,與結構函數在這方面是一樣。但析構函數不帶任何參數。3.一個類有一個也只有一個析構函數,這與結構函數不一樣。析構函數能夠默認。4.對象注銷時,系統自動調用析構函數,按組員在類中申明次序逆序撤消組員(釋放存放空間)。【例4.2】定義一個矩形類有些情況,不需要顯示定義析構函數。查找資料,什么情況下需要什么情況下不需要?能否舉例說明想一想:什么工作?41/1314.4引用與復制結構函數

4.4.1 引用

4.4.2 復制結構函數

4.4.3組員對象與結構函數42/1314.4.1引用引用導入:

參數傳遞傳值方式在函數域中為參數重新分配內存,而把實參數值傳遞到新分配內存中。它優點是有效防止函數副作用。

問題:假如要求改變實參值,怎么辦呢?假如實參是一個復雜對象,重新分配內存會引發程序執行效率大大下降,怎么辦呢?

有一個導出型數據類型—引用(reference)能夠處理上面難題。引用又稱別名(alias)。43/1314.4.1引用

引用定義:

引用是給一個已經定義對象/變量重新起一個別名,而不是定義一個新變量,定義格式為:類型&引用變量名=已定義過變量名;比如:doublenumber;double&newnum=number;newnum是新定義引用類型變量,它是變量number別名。

引用主要用于函數之間數據傳遞。44/1314.4.1引用

newnum是變量number別名,C++系統不為引用類型變量分配內存空間。內存分配見下列圖:

number稱為引用newnum關聯變量。“&”(讀作ampersand)在這里是引用說明符。必須注意number和newnum都是double類型。如在程序中修改了newnum也就是修改了number,兩位一體。注意:對數組只能引用數組元素,不能引用數組(數組名本身為地址)。45/131const引用(不嚴謹):指向const對象引用 constintval=1024;constint&refval=val;

int&ref2=val;//error:nonconstreferencetoaconstobject課下查找,以下語句是否正當,并解釋:inti=34;doublej=65.14;constint&ref1=34;int&ref3=24;constint&ref2=ref1+i;int&ref4=ref1+i;constint&ref5=j;可參考書本p.13346/1314.4.1引用【例4.4】引用作為函數返回值普通函數返回值時,要生成一個暫時變量作為返回值副本,而用引用作為返回值時,不生成值副本。【例4.5】

返回值為引用函數作為左值(選讀)【例4.3】引用作為函數參數。采取引用調用時,將對實參進行操作。注意:采取引用返回方式時,返回不能是函數中局部變量,這時返回局部變量地址已經失效。引用方式返回最慣用是由引用參數傳遞過來變量(見例4.5),其次是全局變量,這么返回變量地址是有效。47/1314.4.2 復制結構函數復制結構函數引入:

同一個類對象在內存中有完全相同結構,假如作為一個整體進行復制是完全可行。這個復制過程只需要復制數據組員,而函數組員是共用(只有一份代碼)。在建立對象時可用同一類另一個對象來初始化該對象,這時所用結構函數稱為復制結構函數(CopyConstructor)。CGoods類,復制結構函數為:CGoods(CGoods&cgd){Strcpy(Name,cgd.Name);Price=cgd.price;Amount=cgd.Amount;Total_value=cgd.Total_value;}復制結構函數形參通常申明為const:CGoods(constCGoods&cgd){....}思索:為何?48/1314.4.2 復制結構函數

復制結構函數特征:1.

復制結構函數參數必須采取引用。*在C++中按值傳遞一個參數時,會在函數中重新分配一塊內存建立與參數同類型變量或對象,再把參數數據組員賦給新變量或對象。在建立這個對象時,編譯器就會自動為這個對象調用復制結構函數。假如其參數是真實對象而不是引用,則又會引入新一輪調用復制結構函數過程,出現了無窮遞歸。CGoods(CGoodscgd){......}49/1314.4.2 復制結構函數

2.

系統會自動提供稱為默認復制結構函數(無顯式定義),亦稱為默認按組員初始化。按組員作復制是經過依次復制每個數據組員實現。4.

在一些情況下,它對類與對象安全性和處理正確性還不夠(有指針數據組員或為組員分配資源?),這時就要求提供顯式復制結構函數和復制賦值操作符定義。3.賦值運算符“=”稱默認按組員復制賦值操作符(OverloadedAssignmentOperator)

,同類對象之間能夠用“=”直接復制。50/1314.4.2 復制結構函數

實例:CGoodCar1(“夏利”,30,98000.00);//調用三個參數結構函數CGoodCar2=Car1;//調用復制結構函數Car2=Car1;//調用重載賦值函數(復制賦值操作)CGoodCar3(Car1);//調用復制結構函數,Car1為實參這么三個對象初始化結果完全一樣。注意:在類定義中假如沒有顯式給出結構函數時,并不是不用結構函數,而是由系統自動調用默認結構函數或默認復制結構函數。假如有程序設計者定義結構函數(包含復制結構函數),則按函數重載規律,調用適當結構函數。51/1314.4.2 復制結構函數隱含復制結構函數使用:當函數形參是非引用(p.125)類型,調用函數時,進行形參加實參結合時使用。這時要在內存新建立一個局部對象,并把實參復制到新對象中。2.當函數返回值是非引用(p.125)類型,函數執行完成返回調用者時使用。理由也是要建立一個暫時對象,再返回調用者。因為局部對象在離開建立它函數時就消亡了,不可能在返回調用函數后繼續生存,所以編譯系統會在調用函數表示式中創建一個無名暫時對象,該暫時對象生存周期只在函數調用處表示式中。所謂return對象,實際上是調用復制結構函數把該對象值拷入暫時對象。假如返回是變量,處理過程類似,只是不調用結構函數。52/1314.4.3 組員對象與結構函數聚合(aggregation):

類中組員,除了組員數據和組員函數外,還有組員對象,即用其它類對象作為類組員。使用組員對象技術稱為聚合。組員對象是實體,系統不但為它分配內存,而且要進行初始化。classstudentID{....};classstudent{

studentIDm_id;charname[20];student(char*pname,longpid=0):m_id(pid){...}};53/1314.4.3 組員對象與結構函數【例4.6】含有組員對象類結構函數

含對象組員析構函數:

因為析構函數沒有參數,所以包含組員對象類析構函數形式上并無特殊之處。不過撤消該類對象時,會首先調用自己析構函數,再調用組員對象析構函數,調用次序與初始化時次序相反。54/1314.4.3 組員對象與結構函數結構函數和析構函數調用規則:

1.對全局定義對象,當程序進入入口函數main之前對象就已經定義,那時要調用結構函數。整個程序結束時調用析構函數。

2.對于局部定義對象,每當程序控制流抵達該對象定義處時,調用結構函數。當程序控制走出該局部域時,則調用析構函數。

3.對于靜態局部定義對象,在程序控制首次抵達該對象定義處時,調用結構函數。當整個程序結束時調用析構函數。55/1314.4.3 組員對象與結構函數

在正確定義了結構函數和析構函數前提下,在一個健康程序中,每個創建對象必定有一個而且只有一個撤消動作。注意:先建立對象后撤消。【例4.7】演示對象創建和撤消對應關系56/1314.5 運算符重載運算符重載概念:

運算符重載是特殊函數重載,必須定義一個函數,并通知C++編譯器,當碰到該重載運算符時調用此函數。這個函數叫做運算符重載函數,通常為類組員函數。運算符重載函數定義:返回值類型類名::operator重載運算符(參數表){……}operator是關鍵字,它與重載運算符一起組成函數名。因函數名特殊性,C++編譯器能夠將這類函數識別出來。inta(1),b(2),c;c=a+b;classXx,y,z;z=x+y;57/131細解運算符重載:復數類+重載:ComplexComplex::operator+(Complexc){

//顯式說明局部對象

ComplexTemp(Real+c.Real,Image+c.Image);

//注意:直接寫對象c私有組員,不用調c公有函數處理

returnTemp;}Complexc2,c3;c2+c3;--->

c2.operator+(c3);函數c2.operator創建一個局部Complex對象Temp,把出現在表示式中兩個Complex類對象c2和c3實部之和及虛部之和暫存其內,然后把這個局部對象返回,賦給Complex類對象c(注意這里調用了復制結構函數生成一個無名暫時對象過渡)。參見圖4.8。4.5 運算符重載classComplex{doubleReal,Image;...};思索:此語句被調用到執行完成,執行了幾次結構函數?58/131Temp.Real=Real+c2.Real;Temp.Image=Image+c3.Image;c=return(Temp);RealImagec.Realc.Image=+局部對象Temp當前對象c2形參對象c圖4.8顯式說明暫時對象“+”運算符執行過程隱式返回計算結果:

省略局部Complex對象TempComplexComplex::operator+(doubled){returnComplex(Real+d,Image);}//隱式說明局部對象在return后面跟表示式中調用是類結構函數,它為無名對象賦值(初始化),返回值就是該無名對象。

調用兩次結構函數59/1314.5 運算符重載說明:ComplexComplex::operator+(Complexc){ComplexTemp(Real+c.Real,Image+c.Image);returnTemp;}當組員函數參數為同一類(class)對象或它引用,在函數體內使用參數對象私有數據組員時,可用對象名加組員訪問操作符點號進行。從邏輯上講,每個對象有自己組員函數,訪問同類其它對象私有數據組員應經過該對象公有函數,不能直接訪問。但在物理上只有一個組員函數代碼,所以直接訪問是合理。僅在組員函數中能夠這么做。【例4.8】復數類,應用它進行復數運算思索:1.這么函數設計有沒有問題?2.可否改為:Complex

&

Complex::operator+(Complexc){ComplexTemp(Real+c.Real,Image+c.Image);returnTemp;}60/1314.5 運算符重載引用作為參數:ComplexComplex::operator+(constComplex&c){

returnComplex(real+c.real,Image+c.Image);}注意:參數采取對象引用而不是對象本身,調用時不再重新分配內存建立一個復制對象,函數效率會更高。而在引用形式參數類型說明前加const關鍵字,表示被引用實參是不可改變,如程序員不妥心在函數體中重新賦值了被引用實參,

C++編譯器會認為犯錯。調用一次結構函數61/1314.5 運算符重載const引用(指向const對象引用)深入說明:引用在內部存放是被引用對象地址,不可尋址值是不能引用;當引用作為形參時,實參也不能使用不可尋址值,更不可能進行類型轉換(如:實數轉換為整數)。不過const引用不一樣,它是只讀,為了絕對確保不會發生誤改,編譯器實現const引用時,生成一個暫時對象,引用實際上指向該暫時對象,但用戶不能訪問它。所以const引用能夠實現不可尋址值(包含字面常量)引用。比如:doubledval=1024;constint&ri=dval;是正確,編譯器將其轉換為:doubledval=1024;inttemp=dval;constint&ri=temp;因有暫時對象,引用和類型轉換都實現了。當const引用作為形參時,實參也能使用不可尋址值,并能進行類型轉換。62/1314.5 運算符重載默認復數復制賦值操作符:函數申明:Complex&Complex::operator=(constComplex&c){ Real=c.Real;Image=c.Image; return*this;}默認賦值操作返回對象本身引用,它能夠進行連續賦值。Complexa,b,c;a=b;c=a=b;63/1314.5 運算符重載本例中重載賦值運算符“=”取代了默認賦值操作,返回一個復數暫時變量,盡管該復數生命期僅在使用賦值號表示式(如a=b=c)中,卻也能進行連續賦值。但它執行效率和代碼簡練性較差。書本例子:ComplexComplex::operator=(Complexc){//重載= Complextemp;//定義temp為可返回Complex類型值,使=可連續使用

temp.Real=c.Real;temp.Image=c.Image; Real=temp.Real;Image=temp.Image;

returntemp;}64/1314.5 運算符重載

2.

當用類組員函數實現運算符重載時,運算符重載函數參數(當為雙目運算符時)為一個或(當為單目運算符時)沒有。運算符左操作數一定是對象,因為重載運算符是該對象組員函數,而右操作數是該函數參數。(隱含*this)3.

單目運算符“++”和“--”存在前置與后置問題。前置“++”格式為:返回類型類名::operator++(){……}

而后置“++”格式為:返回類型類名::operator++(int){……}

后置“++”中參數int僅用作區分。小結:

1.運算符重載函數函數名必須為關鍵字Operator加一個正當運算符。在調用該函數時,將右操作數作為函數實參。65/1314.5 運算符重載4.優先級和結合性是固定 x==y+z;x.operator==(y.operator+(z))66/1314.5 運算符重載運算符運算符名稱禁止重載理由?:三目條件運算符C++中沒有定義三目運算符語法.和.*組員與組員指針操作符為確保組員操作符對組員訪問安全性::作用域操作符該操作符右操作數不是表示式sizeof類型字長操作符該操作符操作數為類型名,不是表示式表5.1C++中不允許重載運算符5.C++中只有極少數運算符不允許重載。

67/1314.5 運算符重載問題:doubled=05;Complexc;例5.7中:

c=c+d;語句,改為

c=d+c;因為d不是Complex對象,C++編譯器將無法找到適當重載“+”運算符對應函數,最終給出犯錯信息。怎樣處理?

68/1314.6 友元在C++中友元(friend)函數允許在類外訪問該類中任何組員,就象組員函數一樣。友元函數用關鍵字friend說明。上節答案:用友元函數重載運算符“+”,能夠實現c=d+c;69/1314.6 友元classComplex{……

friendComplexoperator+(double,Complex);

};//opration+說明為類Complex類友元函數,

//friend只用于類說明中,定義時不加friendComplexoperator+(doubled,Complexc){returnComplex(d+c.Real,c.Image);}//注意友元不是組員函數,但以直接訪問私有組員intmain(void){…… c=d+c1;c.print();return0;}解釋:d+c被C++編譯器解釋為:operator+(d,c)70/1314.6 友元友元函數重載運算符形式:+有三種形式。另兩個申明為:friendComplexoperator+(Complex,Complex);friendComplexoperator+(Complex,double);涵蓋實數與復數,復數與復數,復數與實數相加三種情況。能夠僅使用友元函數friend

complexoperator+(complex,complex);實數被默認結構函數強制轉換為虛部為零復數。d+c1被解釋為:operator+(complex(d),c1)注意:傳值,在函數內是建立了兩個復數對象,而把實參值傳進去,進行運算。參見圖5.9。71/1314.6 友元比較:友元函數能夠有兩個參數,而對應組員函數只有一個參數,所以友元函數使用能夠更靈活、更方便。改進:

Operator+友元函數申明可使用引用類型變量friendComplexoperator+(constComplex&c1,

constComplex&c2)

圖5.9友元函數operator+執行過程內存分配【例4.8_1】用友元函數重載運算符72/1314.6 友元單目運算符前“++”組員函數重載方式以下:ComplexComplex::operator++(){

returnComplex

(++Real,++Image);}采取組員函數方式重載與使用都很方便。友元函數重載后置“++”以下:friend

Complexoperator++(Complex&c,int)

{//注意友元方式與前者區分

returnComplex(c.Real++,c.Image++);}采取引用類型,后“++”是直接施加于實參。不然施加于副本,而實參不變。注意:復制賦值運算符(=)重載必須為組員函數,不可為友元函數。因為默認復制賦值運算符(=)是組員函數,友元函數不能取代它。73/131友元函數注意點:

1.

友元函數不是類組員函數,在函數體中訪問對象組員,必須用對象名加運算符“.”加對象組員名。但友元函數能夠訪問類中全部組員,普通函數只能訪問類中共有組員。

2.

友元函數不受類中訪問權限關鍵字限制,能夠把它放在類公有、私有、保護部分,但結果一樣。

3.

某類友元函數作用域并非該類作用域。假如該友元函數是另一類組員函數,則其作用域為另一類作用域,不然與普通函數相同。友元類:整個類能夠是另一個類友元。友元類每個組員函數都是另一個類友元函數,都可訪問另一個類中保護或私有數據組員。定義方法以下:classA{……friendclassB;//申明B為A友元類

……};提議:萬不得已不要使用友元74/1314.7靜態組員

由關鍵字static修飾說明類組員,成為靜態類組員(staticclassmember)。但與函數中靜態變量有顯著差異。類靜態組員為其全部對象共享,不論有多少對象,靜態組員只有一份存于公用內存中。4.7.1靜態數據

4.7.2靜態函數組員(選讀)

Student{staticlongclassID;};intStudent::classID=191131;Students1,s2,s3;Student{

longclassID;};Students1,s2,s3;75/1314.7.1靜態數據靜態數據組員定義與使用:在類定義中,用關鍵字static修飾數據組員為靜態數據組員。該類全部對象共享由系統為靜態組員分配一個存放空間,而這個存放空間是在編譯時分配,在定義對象時不再為靜態組員分配空間。靜態數據是該類全部對象所共有,可提供同一類全部對象之間信息交換捷徑。靜態數據組員屬于整個類,使用時可用以下格式:類名::靜態數據組員名76/1314.7.1靜態數據【例4.9】用靜態數據組員計算由同一類建立對象數量執行程序后輸出:對象數量=1//a[0]結構函數產生對象數量=2//a[1]結構函數產生對象數量=3//a[2]結構函數產生對象數量=2//a[2]析構函數產生對象數量=1//a[1]析構函數產生對象數量=0//a[0]析構函數產生77/1314.7.2靜態函數組員(選讀)靜態函數組員使用:函數組員說明為靜態,將與該類不一樣對象無關。靜態函數組員調用,在對象之外能夠采取下面方式:類名::函數名(對象名,參數表);任一類對象名.函數名(對象名,參數表);

靜態函數組員多為公有。在例4.8中復數類中函數組員print(),改為靜態則能夠下表示:static

voidprint(complex

&ob){cout<<”Real=”<<ob.Real<<’\t’

<<”Image=”<<ob.Image<<’\n’;}參數是為了告訴C++系統應取哪一個對象數據。78/1314.8結構結構類型引入:

在C++中結構(structure)與類幾乎是完全一樣類型,差異僅僅在于默認情況下結構組員為公有。在C語言階段,結構就已存在,但它只有公有數據組員。正因為如此,C++程序員依然使用結構,不過只為結構安排公有數據組員。因為這么程序更易讀易懂。在程序設計中常把結構類型數據作為類數據組員。

C格調定義:struct結構類型名{

類型名變量1;《類型名變量2;…;》};//最終分號不可少79/1314.8結構實例:structinventory{//庫存貨物chardescription[15];//貨物名稱charno[10];//貨號intquantity;//庫存數量doublecost;//成本doubleretail;};//零售價格structemployee{//員工charname[27];//員工姓名charaddress[30];//家庭住址longintzip;//郵政編碼longinttelenum;//聯絡電話doublesalary;};//工資80/1314.8結構變量定義與初始化:結構是一個派生數據類型,定義結構時并不分配存放空間,只有定義了結構類型變量,編譯系統才為結構變量分配存放空間。定義變量方法以下:inventorycar,motor;

初始化是用花括號中次序填入結構中(公有數據)組員初始值完成:employeeemp1={“朱明”,“四牌樓2號”,210096,3792666,2430.0},emp2={“沈俊”,“丁家橋15號”,210009,3273389,1920.0};結構變量訪問與類一樣,可使用組員訪問操作符之一:點操作符,對組員一個個進行:變量名.組員名81/1314.8結構結構類型使用說明:

(1)

與同類對象之間能夠復制一樣,同結構類型變量之間也能夠作為整體相互賦值(復制)。

(2)結構變量也能夠作為函數參數和返回值,結構作為參數能夠按值(復制)進行傳遞,也能夠按引用傳遞。

(3)在程序文件中強烈推薦將結構類型定義放在全部函數外面,這么程序文件中各個函數能夠按需要在各個函數中申明局部結構變量。在各函數中定義結構類型,即使兩個函數中定義完全一樣,系統也完全認為是兩種結構類型。

82/1314.8結構(4)結構可以嵌套:structmail{charaddress[30];//地址longintzip;//郵政編碼longinttelenum;};//電話號碼structemployee{charname[25];//員工姓名mailaddinfo;//結構作為成員,嵌套doublesalary;};//工資用連續點號來訪問結構變量結組成員中成員:employeeemp1={“朱明”,“四牌樓2號”,210096,3792666,2430.0};cout<<emp1.addinfo.telenum;輸出為3792666。83/1314.8結構聯合(選讀):

union

共同體變量名{類型組員名1;《類型組員名2;…;》};

聯合(union)與結構區分是:結構變量各組員同時被分配了各自獨立內存區,而聯合變量各個組員存放開始地址都相同,所以在任一時刻聯合變量只能存放一個組員。

系統為聯合變量分配空間時按需要最大存放量組員大小分配內存空間。聯合被稱為一個特殊類(它因編譯器不能知道組員類型,而沒有結構函數和析構函數,所以聯合對象不是由結構函數生成。故稱特殊類)。84/1314.8結構用途:聯合經典用途是按不一樣方式訪問同一塊內存。比如:unionnum{

intk;

charch[2];}a;圖4.10聯合變量a內存分配系統為變量a分配了4個字節空間。假如以ch[1]記樓層號,以ch[0]記同一樓層房間號,如15樓8號房間則可賦值:a.ch[1]=15;a.ch[0]=8;見圖4.10。假如需要把全部房間次序排號,則可用a.k來讀取一個整型數(15*256+8),1樓1號房間排在第一,樓層越高、同一層房間號越大房間排得越后。85/1314.9名字空間域和類域(選讀)

在C++中支持三種域:局部域、名字空間域和類域。名字空間域申明:

名字空間域相當于一個愈加靈活文件域(全局域),能夠用花括號把文件一部分括起來,并以關鍵字namespace開頭給它起一個名字:namespacens1{

floata,b,c;fun1(){……}…}花括號括起來部分稱申明塊。申明塊中能夠包含:類、變量(帶有初始化)、函數(帶有定義)等。86/1314.9名字空間域和類域(選讀)名字空間域訪問:在域外使用域內組員時,需加上名字空間名作為前綴,后面加上域操作符“::”

。這里添加了名字空間名稱組員名被稱為限定修飾名(qualifiedname)。如:ns1::a,ns1::fun1()等等。

87/1314.9名字空間域和類域(選讀)名字空間域嵌套:

名字空間域可分層嵌套,一樣有分層屏蔽作用。比如:namespacecplusplus_primer{

namespaceMatrixlib{ //名字空間嵌套

classmatrix{……} //名字空間類組員matrix …...}}訪問matrix,可寫限定修飾名:cplusplus_primer::Matrixlib::matrix

最外層名字空間域稱為全局名字空間域(globalnamespacescope),即文件域。

88/1314.9名字空間域和類域(選讀)using申明:使用using申明可只寫一次限定修飾名。using申明以關鍵字using開頭,后面是被限定修飾(qualified)名字空間組員名:usingcplusplus_primer::Matrixlib::matrix;

//名字空間類組員matrixusing申明以后在程序中使用matrix時,就能夠直接使用組員名,而無須使用限定修飾名。 89/1314.9名字空間域和類域(選讀)using指示符:

使用using指示符能夠一次性地使名字空間中全部組員都能夠直接被使用,比using申明方便。using指示符以關鍵字using開頭,后面是關鍵字namespace,然后是名字空間名。標準C++庫中全部組件都是在一個被稱為std名字空間中申明和定義。在采取標準C++平臺上使用標準C++庫中組件,只要寫一個using指示符:usingnamespacestd;就能夠直接使用標準C++庫中全部組員。這是很方便。90/1314.9名字空間域和類域(選讀)名字空間域引入,主要是為了處理全局名字空間污染(globalnamespacepollution)問題,即預防程序中全局實體名與C++各種庫中申明全局實體名沖突。名字空間域補充說明:名字空間能夠不連續,分為多段,但它們仍是同一個名字空間。名字空間域不能定義在函數申明、函數定義或類定義內部。91/1314.9名字空間域和類域(選讀)類域:

類體部分稱為類域。在類域中說明標識符僅在該類類域內有效。必須加上“類名::”作限定修飾。類實體——對象中公有組員也能夠在對象之外訪問,但必須使用組員訪問操作符“.”,對象名+“.”+組員名。定義類本身目標就是要實現一個封裝性,對外是封閉,對內是開放,在程序中并不總是需要用組員訪問符之類來引用類組員。多數程序代碼本身就在類域中,這些程序能夠直接訪問類組員。在類域中類組員在類體中被申明次序一樣很主要,后申明組員不能被先申明組員引用。92/1314.9名字空間域和類域(選讀)標識符解析:

編譯器對名字(標識符)解析分兩步,第一步查找在申明中用到名字,包含數據組員和函數組員申明中用到參數類型,第二步才是函數組員體內名字。比如:classstring{ //字符串類public:

typedef

intindex_type;//為易讀易懂用下標型命名

charGetstringElement(index_typeelem){ returnAstring[elem];} //Astring未說明private:

charAstring[30]; //Astring后說明};表面上看是錯;實際上是正確。因為Astring名字解析是在第一步,而函數使用它是在第二步。93/1314.10面向對象程序組織與Windows下實現

在本小節中,我們引入怎樣實際實現面向對象程序設計概念與方法。使讀者了解面向對象設計程序中各對象是怎樣協調工作,以及為何在Windows操作系統下才能真正實現面向對象程序設計。94/1314.10面向對象程序組織與Windows下實現

面向過程程序結構:程序=算法+數據結構。算法實際上就是功效抽象。在面向過程程序設計中程序是模塊化,模塊是分層次,層與層之間是一個從上往下調用關系。圖4.11給出了這種層次模塊調用關系。圖4.11面向過程程序設計程序組織

95/1314.10面向對象程序組織與Windows下實現

功效抽象是困難,而且極難全方面,一旦要處理問題發生一點小改變,功效塊就要重編,而一個功效塊又被多個上層模塊調用(圖中稱任務塊),它們要求有變了,有沒變,這就給重編帶來極大困難。96/1314.10面向對象程序組織與Windows下實現

面向對象程序結構:對象=(算法+數據結構),程序=對象+對象+……+對象+消息。這里程序是由一個個封裝對象組成,而對象是由緊密結合在一起算法和數據結構組成,對象中有數據和對數據操作,它帶來了計算機效率下降和程序員效率上升及工作難度下降。97/1314.10面向對象程序組織與Windows下實現

對象與對象之間怎樣建立有效聯絡,相互調用思想顯著不行。實際上采取是用消息傳遞機制來協調各對象運行,如圖4.12:

圖4.12面向對象程序組織

98/1314.10面向對象程序組織與Windows下實現消息:

消息是對象之間相互請求或相互協作路徑,是要求某個對象執行其中某個功效操作規格說明。消息傳遞是對象與其外部世界相互關聯唯一路徑。對象能夠向其它對象發送消息以請求服務,也能夠響應其它對象傳來消息,完成本身固有一些操作,從而服務于其它對象。99/1314.10面向對象程序組織與Windows下實現消息和方法:

因為對象操作主要用來響應外來消息并為其它對象提供服務,所以它們也被稱作“外部服務”。消息是客觀世界中對象之間通信信號,是要求某個對象執行其中某個功效操作規格說明。對象動作取決于發送給該對象消息,消息通知對象要求完成功效。也就是說,消息傳遞完成是“做什么”任務,并認為接收消息對象知道怎樣去做,對象激活該功效,完成任務。100/1314.10面向對象程序組織與Windows下實現

方法描述了對象能力,從程序設計角度看它是對象實現功效操作代碼段。方法與消息相互對應,每當對象收到一個消息后,除了知道“做什么”外,還必須知道和決定“怎樣做”。方法就是對象中決定“怎樣做”操作代碼,方法就是實現每條消息詳細功效伎倆。面向對象程序設計并沒有給出或指定詳細方法來實現這個“消息傳遞”機制,只是提出這么一個理念。實際上對C++而言,這一機制是由操作系統完成。101/1314.10面向對象程序組織與Windows下實現消息傳遞,事件驅動:Windows系統支持多個應用程序同時執行,在界面形式上,它支持多個窗口同時活動。它運行機制就是“消息傳遞,事件驅動(messagebased,eventdriven)”。

Windows系統使用事件驅動編程模式。所謂事件含義非常廣泛。輸入設備動作,如敲打鍵盤、按鼠標等會產生一系列事件(注意不是一個事件)。操作系統所作一舉一動也被看成某種類型事件,應用程序也會產生各種事件。事件用來標識發生某件事情。

Windows系統對于應用程序環境中發生每一個事件都會以對應某種消息形式標識,并放入對應Windows建立消息隊列中,然后由對應應用程序或窗口函數去處理。102/1314.10面向對象程序組織與Windows下實現圖5.13windows操作系統下應用程序

103/131第五章類與對象結束謝謝!104/1314.1.2 組員函數定義void

CGoods::RegisterGoods(charname[],intamount,floatprice){strcpy(Name,name);//字符串復制函數Amount=amount;Price=price;}void

CGoods::CountTotal(void){Total_value=Price*Amount;}void

CGoods::GetName(charname[]){strcpy(name,Name);}int

CGoods::GetAmount(void){return(Amount);}float

CGoods::GetPrice(dvoi){return(Price);}float

CGoods::GetTotal_value(void){return(Total_value);}105/131【例4.1】商品類對象應用實例【例4.1】商品類對象應用實例:#include<iostream>#include<iomanip>#include<string>usingnamespacestd;//省略了類定義int

main(){CGoods car;charstring[21];int number;floatpr;106/131組員名Name[21];Amount;Price;Total_value;10minicar5210minicar52string[21]numberPrminicar52minicarcout<<“請輸入汽車型號:”

;cin.getline(string,20);//輸入串長必須小于20cout<<“請依次輸入汽車數量與單價:”

;cin>>number>>pr;car.RegisterGoods(string,number,pr);car.CountTotal();string[0]=’\0’;//字符串string清零car.GetName(string);//string賦值car.Namecout<<setw(20)<<string<<setw(5)<<car.GetAmount();//Acout<<setw(10)<<car.GetPrice()<<setw(20)<<car.GetTotal_value()<<endl;//Breturn0;}107/131【例4.1_1】完整商品類對象應用實例

classCGoods{private:

char Name[21]; int Amount;

float Price;float To

溫馨提示

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

評論

0/150

提交評論