C++課件 第14章 構(gòu)造函數(shù)_第1頁
C++課件 第14章 構(gòu)造函數(shù)_第2頁
C++課件 第14章 構(gòu)造函數(shù)_第3頁
C++課件 第14章 構(gòu)造函數(shù)_第4頁
C++課件 第14章 構(gòu)造函數(shù)_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、第十四章 構(gòu)造函數(shù) 面向?qū)ο笳Z言的構(gòu)造函數(shù)是很重要的,它涉及到對象的構(gòu)造及效率,但構(gòu)造函數(shù)又很復(fù)雜。在JAVA語言和本門課前面的內(nèi)容中,以及很多編程書中,為突出構(gòu)造函數(shù)的基本概念和基本特性,有意的忽略了構(gòu)造函數(shù)的復(fù)雜性?,F(xiàn)在,在類、繼承、多態(tài)講完后,作為單獨的一章,集中講一下C+的構(gòu)造函數(shù),為了有連續(xù)性,其中有一些內(nèi)容與課件前面 “基于對象/面向?qū)ο蟆?相關(guān)章節(jié)(5,6,9,10章)的內(nèi)容重復(fù)。課件前面有關(guān)構(gòu)造函數(shù)講的比較模糊的地方,與本章課件為準(zhǔn)。雖然講的是C+的構(gòu)造函數(shù),但其中一部分內(nèi)容對其它面向?qū)ο蟮恼Z言(包括JAVA)也有參考價值。本章內(nèi)容包括:n 單個類的構(gòu)造函數(shù);n 繼承方式下子類

2、的構(gòu)造函數(shù);一、單個類的構(gòu)造函數(shù);1一般特性 構(gòu)造函數(shù)的作用是創(chuàng)建對象,進(jìn)行對象的內(nèi)存分配、初始化成員變量等工作。析構(gòu)函數(shù)的作用與構(gòu)造函數(shù)相反。C+構(gòu)造函數(shù)主要特點:l 構(gòu)造函數(shù)的名字與類名相同l 構(gòu)造函數(shù)也是成員函數(shù),聲明在類體內(nèi),實現(xiàn)在類體外或在類體內(nèi)。l 構(gòu)造函數(shù)無需聲明返回類型和返回值(有系統(tǒng)內(nèi)部使用的隱含返回值)。l 構(gòu)造函數(shù)可以重載。l 當(dāng)類沒有定義構(gòu)造函數(shù)時,系統(tǒng)默認(rèn)一個。C+析構(gòu)函數(shù)特點:l 析構(gòu)函數(shù)的名字是在類名前加l 析構(gòu)函數(shù)也是成員函數(shù),聲明在類體內(nèi),實現(xiàn)在類體外或在類體內(nèi)。l 析構(gòu)函數(shù)無需聲明返回類型和返回值,也無需形參。l 析構(gòu)函數(shù)不可以重載,一個類只能有一個析構(gòu)函數(shù)

3、。l 當(dāng)類沒有定義析構(gòu)函數(shù)時,系統(tǒng)默認(rèn)一個。2. 默認(rèn)的構(gòu)造函數(shù) Q1:當(dāng)類沒有定義構(gòu)造函數(shù)時,系統(tǒng)默認(rèn)一個。注本章所有程序均在VC8.0下調(diào)試?yán)?: #include "stdafx.h"#include "iostream"using namespace std;class Apublic: unsigned short int i;int _tmain(int argc, _TCHAR* argv) A a1; cout<<a1.i; cout<<a1.i輸出了一個隨意指定的整數(shù),說明對象a1被默認(rèn)的構(gòu)造函數(shù)創(chuàng)建了,但這個程

4、序在編譯的時侯告警,運行時報錯,按“確定”后才輸出正確結(jié)果。為什么會這樣?把程序改一下:例2:以下程序在VC8.0下調(diào)試#include "stdafx.h"#include "iostream"using namespace std;class Apublic: unsigned short int i; virtual int fun()return 1; /增加了一個虛函數(shù) ;int _tmain(int argc, _TCHAR* argv) /不能寫成A(a1),/但可寫成A* a1=new A()或A* a1=new AA a1; cout&

5、lt;<a1.i; 運行正常。原來,很多C+書說錯了,“當(dāng)類沒有定義構(gòu)造函數(shù)時,系統(tǒng)默認(rèn)一個”是有先決條件的:如果一個類中沒有定義任何的構(gòu)造函數(shù),那么編譯器只有在以下三種情況,默認(rèn)的構(gòu)造函數(shù)才會正確工作:( 1)如果類有虛擬成員函數(shù)或者虛擬繼承父類(即有虛擬基類)時;( 2)如果類的基類有構(gòu)造函數(shù)(可以是用戶定義的構(gòu)造函數(shù),或編譯器提供的默認(rèn)構(gòu)造函數(shù)); ( 3)在類中的所有非靜態(tài)的對象數(shù)據(jù)成員,它們所屬的類中有構(gòu)造函數(shù)(可以是用戶定義的構(gòu)造函數(shù),或編譯器提供的默認(rèn)構(gòu)造函數(shù))。記住上述幾條有點費勁,所以,我們還是自已寫一個構(gòu)造函數(shù)好,而一般不要用系

6、統(tǒng)默認(rèn)的。Q2:當(dāng)自已寫一個構(gòu)造函數(shù)時,無論有參和無參,默認(rèn)構(gòu)造函數(shù)均無效例3:#include "stdafx.h"#include "iostream"using namespace std;class Apublic: int i; virtual int fun()return 1; A()i=1;cout <<"構(gòu)造函數(shù)1被執(zhí)行" A(int x)i=x;cout <<"構(gòu)造函數(shù)2被執(zhí)行"int _tmain(int argc, _TCHAR* argv) A a1; cout&l

7、t;<a1.i; A a2; cout<<a2.i; A a3(2); cout<<a3.i; 結(jié)論是對的,構(gòu)造函數(shù)A()被執(zhí)行了兩次。Q3:為什么用系統(tǒng)默認(rèn)或無參構(gòu)造函數(shù)實例化棧對象時,不能用A a1(),只能用A a的語法?例4:#include "stdafx.h"#include "iostream"using namespace std;class Apublic: int i; virtual int fun()return 1; A()i=1;cout <<"構(gòu)造函數(shù)1被執(zhí)行"

8、A(int x)i=x;cout <<"構(gòu)造函數(shù)2被執(zhí)行"int _tmain(int argc, _TCHAR* argv) A* a4=new A();/正確A* a5=new A; /正確A a6();/創(chuàng)建棧對象,應(yīng)寫為A a6 原因是:A a6()這種寫法,編譯器會誤以為它是個無參的函數(shù)聲明,返回類型為A。所以,用系統(tǒng)默認(rèn)或無參構(gòu)造函數(shù)創(chuàng)建棧對象時,只能用A a6這種寫法。Q4 類體內(nèi)(類的聲明部分)不允許初始化成員變量,初始化成員變量是構(gòu)造函數(shù)要做的事(這一部分與課件第六章基本重復(fù),以本章為準(zhǔn))。例5:class Tpublic: int=1; /這

9、是不允許的 ;這樣的規(guī)定是合乎面向?qū)ο笏枷氲?,類是一個“數(shù)據(jù)類型”的抽象,類成員有具體值的時侯就變成一個對象了。創(chuàng)建對象的分工給構(gòu)造函數(shù)去做比較好。下面的例子哪里有錯?例6:(課件第6章Q6有這個例子)class Aprivate:int i = 0; / 錯,成員變量不能在類體內(nèi)初始化const int a = 1; / 錯 static int b = 2; / 錯 static const int c =3; /錯. ?;static const int c =3是對的。C+標(biāo)準(zhǔn)關(guān)于static數(shù)據(jù)成員在類中聲明的描述是:static數(shù)據(jù)成員在類聲明中聲明,在包含類方法的文件中初始化。但

10、如果static成員是整型或枚舉型const,則可以在類聲明中初始化,這是一種例外,不敢保證所有編譯器都能通過(VC8能通過) 作為通用原則,const, static成員變量的初始化只能用兩種方法:(1)一種方式就是在外部初始化,只適合于static或static const(非static變量不能外部初始化)。原因大概是static變量是屬于類的,多個對象共享一個static變量,它在創(chuàng)建對象(調(diào)用構(gòu)造函數(shù))之前就因該存在,否則不能用 類名. static變量名訪問,而且多次構(gòu)造會破壞static變量的值。(2)用構(gòu)造函數(shù)初始化列表。適合于const和一般變量(稍后解釋),不適合stati

11、c(原因同上)。例7:class Apublic: const int a; static int b;const static int c; const static float d; A():a(1)cout<<"OK"<<endl; /初始化列表初始化a; int A:b = 2; /外部初始化b,前面不允許寫static const int A:c=3; /外部初始化c,前面不允許寫static const float A:d=4.5; /外部初始化d,前面不允許寫staticint _tmain(int argc, _TCHAR* argv

12、) A a4; A* a5=new A(); cout<<a4.a<<a4.b<<a4.c<<a4.d<<endl; cout<<a5->a<<a5->b<<a5->c<<a5->d<<endl;上例中,const static int c;可寫成const static int c=3;去掉const int A:c=3;Q5:什么是初始化列表?(這一部分與課件第六章基本重復(fù),以本章為準(zhǔn))初始化列表又叫構(gòu)造函數(shù)初始化列表,它是一個特殊的構(gòu)造函數(shù),可以

13、對類的成員變量(或常量)初始化。其語法為:類名():變量1(表達(dá)式),變量2(表達(dá)式)例如:class CExample public:   int a;    float b;/構(gòu)造函數(shù)初始化列表,也可以寫到類體外    Cexample(): a(0),b(8.8)     /這里可以寫構(gòu)造函數(shù)體,也可以什么也不寫 /構(gòu)造函數(shù)內(nèi)部賦值進(jìn)行初始化,該函數(shù)也可寫到類體外  &#

14、160;Cexample()           a=0;  b=8.8;   上面的例子中兩個構(gòu)造函數(shù)的結(jié)果是一樣的。只是前者顯式的初始化類的成員,后者沒有進(jìn)行顯式的初始化。但兩者有很明顯的區(qū)別:初始化列表在構(gòu)造函數(shù)主體執(zhí)行前就執(zhí)行了,這不僅可以提高效率(有的書聲稱做過實驗,使用初始化列表創(chuàng)建對象的速度比使用賦值構(gòu)造函數(shù)快1/3),更重要的是,適合于繼承條件下子類的初始化。對于C+內(nèi)置的數(shù)據(jù)類型(int,數(shù)組等),初始化列表和一般的構(gòu)

15、造函數(shù)賦值沒有區(qū)別。對引用類型成員變量(比如說對象),為了避免多次構(gòu)造,一般要使用構(gòu)造函數(shù)初始化列表。對于const,必須使用構(gòu)造函數(shù)初始化列表,原因一是const是被類的每個對象獨享的(一個對象的const成員只有一個值,但不同對象的const可能會有不同值,),只能在構(gòu)造函數(shù)中初始化;而一般構(gòu)造函數(shù)的賦值語句不能初始化const(我們知道,常量只能在聲明的時侯賦值,這種賦值應(yīng)該叫初始化),所以不能用一般的構(gòu)造函數(shù)進(jìn)行賦值,只能用構(gòu)造函數(shù)初始化列表。最后,是初始化列表的執(zhí)行順序:它是按聲明順序進(jìn)行的,比如:class CExample public:  

16、; int a;    float b;/構(gòu)造函數(shù)初始化列表,也可以寫到類體外    Cexample(): b(8.8) ,a(0)     /這里可以寫構(gòu)造函數(shù)體,也可以什么也不寫 ;先初始化a,因為a聲明在先。Q6:拷貝初始化構(gòu)造函數(shù) 在課件第五章講過,在JAVA中也學(xué)過沒有什么變化,不再重復(fù)。我們應(yīng)該對對象的深拷貝(傳值)和淺拷貝(傳引用)的概念很清楚。最常用的就是將對象作為函數(shù)的參數(shù),如果不想更改原對象的狀態(tài)就用深拷貝,否則淺

17、拷貝。 二、繼承方式下子類的構(gòu)造函數(shù)(這一部分與課件第九章基本重復(fù),以本章為準(zhǔn)); 當(dāng)一個派生類對象被創(chuàng)建時,其基類對象也被創(chuàng)建,實際上一個派生類對象是由其基類對象和派生類對象“組裝”而成,了解這一點才能了解派生類 構(gòu)造函數(shù)/析構(gòu)函數(shù) 的有關(guān)特性。這一系列的創(chuàng)建過程是用構(gòu)造函數(shù)初始化列表完成的。1. 派生類的構(gòu)造函數(shù)構(gòu)造函數(shù)不能夠被繼承,因此,派生類的構(gòu)造函數(shù)必須通過調(diào)用基類的構(gòu)造函數(shù)來初始化派生類對象。所以,在定義派生類的構(gòu)造函數(shù)時除了對自己的數(shù)據(jù)成員進(jìn)行初始化外,還必須負(fù)責(zé)調(diào)用基類構(gòu)造函數(shù)使基類數(shù)據(jù)成員得以初始化。如果派生類中還有子對象時(比如將某個類的對象作為派生類的成員變量),還應(yīng)包含

18、對子對象初始化的構(gòu)造函數(shù)。派生類構(gòu)造函數(shù)的一般格式如下(使用構(gòu)造函數(shù)初始化列表):派生類名(派生類構(gòu)造函數(shù)總參數(shù)表):基類構(gòu)造函數(shù)(參數(shù)表1),子對象名(參數(shù)表2) /派生類中數(shù)據(jù)成員初始化;派生類構(gòu)造函數(shù)的調(diào)用順序如下:l 基類的構(gòu)造函數(shù)l 子對象類的構(gòu)造函數(shù)(如果有的話)l 派生類構(gòu)造函數(shù)Q1:下面程序的運行結(jié)果:class A private:int a;public: A() a=0;cout<<"Ad" /缺省構(gòu)造函數(shù) A(int i) a=i; cout<<"A" /構(gòu)造函數(shù) ;class B:public Aprivate:int b; A aa; /子對象aapublic:B() b=0;cout<<"Bd"<<endl; /缺省構(gòu)造函數(shù) B(int i, int j, int k);

溫馨提示

  • 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

提交評論