jasmine214--love

          只有當(dāng)你的內(nèi)心總是充滿快樂、美好的愿望和寧?kù)o時(shí),你才能擁有強(qiáng)壯的體魄和明朗、快樂或者寧?kù)o的面容。
          posts - 731, comments - 60, trackbacks - 0, articles - 0

          C++ 構(gòu)造函數(shù)

          Posted on 2010-08-11 13:55 幻海藍(lán)夢(mèng) 閱讀(454) 評(píng)論(0)  編輯  收藏 所屬分類: C++
            原文:http://blog.pfan.cn/xman/41107.html
          1
          )構(gòu)造函數(shù)、析構(gòu)函數(shù)與賦值函數(shù)

          構(gòu)造函數(shù)、析構(gòu)函數(shù)與賦值函數(shù)是每個(gè)類最基本的函數(shù)。它們太普通以致讓人容易麻痹大意,

          其實(shí)這些貌似簡(jiǎn)單的函數(shù)就象沒有頂蓋的下水道那樣危險(xiǎn)。

          每個(gè)類只有一個(gè)析構(gòu)函數(shù)和一個(gè)賦值函數(shù),但可以有多個(gè)構(gòu)造函數(shù)(包含一個(gè)拷貝構(gòu)造函數(shù),其它的稱為普通構(gòu)造函數(shù))。對(duì)于任意一個(gè)類A,如果不想編寫上述函數(shù),C++編譯器將自動(dòng)為A 產(chǎn)生四個(gè)缺省的函數(shù),例如:

          A(void); // 缺省的無參數(shù)構(gòu)造函數(shù)

          A(const A &a); // 缺省的拷貝構(gòu)造函數(shù)

          ~A(void); // 缺省的析構(gòu)函數(shù)

          A & operate =(const A &a); // 缺省的賦值函數(shù)

          這不禁讓人疑惑,既然能自動(dòng)生成函數(shù),為什么還要程序員編寫?原因如下:

          <1>如果使用“缺省的無參數(shù)構(gòu)造函數(shù)”和“缺省的析構(gòu)函數(shù)”,等于放棄了自主“初始化”和“清除”的機(jī)會(huì),C++發(fā)明人Stroustrup 的好心好意白費(fèi)了。

          <2>“缺省的拷貝構(gòu)造函數(shù)”和“缺省的賦值函數(shù)”均采用“位拷貝”而非“值拷貝”的方式來實(shí)現(xiàn),倘若類中含有指針變量,這兩個(gè)函數(shù)注定將出錯(cuò)。

          對(duì)于那些沒有吃夠苦頭的C++程序員,如果他說編寫構(gòu)造函數(shù)、析構(gòu)函數(shù)與賦值函數(shù)很容易,可以不用動(dòng)腦筋,表明他的認(rèn)識(shí)還比較膚淺,水平有待于提高。

          下面以類String 的設(shè)計(jì)與實(shí)現(xiàn)為例,深入闡述被很多教科書忽視了的道理。String的結(jié)構(gòu)如下:

          class String

          { 

          public:   

              String(const char *str = NULL); // 普通構(gòu)造函數(shù)

              String(const String &other); // 拷貝構(gòu)造函數(shù)

              ~ String(void); // 析構(gòu)函數(shù)   

              String & operate =(const String &other); // 賦值函數(shù)

          private: 

              char *m_data; // 用于保存字符串

          };

          2)構(gòu)造函數(shù)是一種特殊的成員函數(shù),無返回值,函數(shù)名與類同名。它提供了對(duì)成員變量進(jìn)行初始化的方法,使得在聲明對(duì)象時(shí)能自動(dòng)地初始化對(duì)象。因?yàn)楫?dāng)程序創(chuàng)建一個(gè)對(duì)象時(shí),系統(tǒng)會(huì)自動(dòng)調(diào)用該對(duì)象所屬類的構(gòu)造函數(shù)。

          例一:class Student

          {

               Student()//默認(rèn)無參無賦值操作構(gòu)造函數(shù)

               {

               }

          }

          Student stu;//聲明對(duì)象

          以上代碼中的無參無操作構(gòu)造函數(shù)即為系統(tǒng)自動(dòng)提供一個(gè)默認(rèn)的構(gòu)造函數(shù),該默認(rèn)構(gòu)造函數(shù)沒有參數(shù),它僅僅負(fù)責(zé)創(chuàng)建對(duì)象而不做任何賦值操作。

          例二:class Student

          {   

               Student()//無參帶賦值操作構(gòu)造函數(shù)

               {

                   memberVariable1=constValue1;

                   memberVariable2=constValue2;

               }

          }

          Student stu;//聲明對(duì)象

          以上代碼中,在默認(rèn)構(gòu)造函數(shù)添加賦值初始化操作,該構(gòu)造函數(shù)將覆蓋默認(rèn)構(gòu)造函數(shù)。該構(gòu)造函數(shù)沒有參數(shù),它不僅負(fù)責(zé)創(chuàng)建對(duì)象而還負(fù)責(zé)成員變量的狀態(tài)初始化。

          例三:class Student

          {   

               Student(type1 value1,type2 value2) //含參帶賦值操作構(gòu)造函數(shù)

               {

                   memberVariable1=value1;

                   memberVariable2=value2;

               }

          }

          Student stu(value1,value2);//聲明對(duì)象

          以上代碼中,在默認(rèn)構(gòu)造函數(shù)中添加參數(shù)和賦值初始化操作,該構(gòu)造函數(shù)將覆蓋默認(rèn)構(gòu)造函數(shù)。該構(gòu)造函數(shù)沒有參數(shù),它不僅負(fù)責(zé)創(chuàng)建對(duì)象而還負(fù)責(zé)傳值對(duì)成員變量進(jìn)行狀態(tài)初始化。

          一旦類中有了一個(gè)帶參數(shù)的構(gòu)造函數(shù)而又沒無參數(shù)構(gòu)造函數(shù)的時(shí)候系統(tǒng)將無法創(chuàng)建不帶參數(shù)的對(duì)象,此時(shí)以下三種聲明都是錯(cuò)誤的:

          Student stu;

          Student *stu = new Student;

          Student *stu = new Student();

           

          例四:class Student

          {

               Student()

               {

               }

               /*Student()

               {

                   memberVariable1=constValue1;

                   memberVariable2=constValue2;

               }*/

               Student(type1 value1,type2 value2)

               {

                   memberVariable1=value1;

                   memberVariable2=value2;

               }

          };

          Student stu; // 聲明對(duì)象—棧對(duì)象

          Student *stu; // 類指針變量—棧對(duì)象

          Student *stu = new Student; // çèStudent *stu = new Student();—堆對(duì)象

           

          Student stu(value1,value2); // 聲明對(duì)象—棧對(duì)象

          Student *stu = new Student(value1,value2); // 聲明對(duì)象—堆對(duì)象

           

              以上代碼中,既有無參(默認(rèn))構(gòu)造函數(shù),又有含參和賦值操作的構(gòu)造函數(shù);既可聲明無參對(duì)象,也可聲明含參初始化對(duì)象。注意new是在堆上動(dòng)態(tài)創(chuàng)建的。

          由于構(gòu)造函數(shù)和普通函數(shù)一樣具有重載特性所以編寫程序的人可以給一個(gè)類添加任意多個(gè)構(gòu)造函數(shù),來使用不同的參數(shù)來進(jìn)行初始化對(duì)象!

          類一旦定義就可以當(dāng)作一種新的數(shù)據(jù)類型,可作為另一個(gè)類的數(shù)據(jù)成員,即類可以嵌套定義。

          類是一個(gè)抽象的概念,并不是一個(gè)實(shí)體,并不能包含屬性值(這里來說也就是構(gòu)造函數(shù)的參數(shù)了),只有對(duì)象才占有一定的內(nèi)存空間,含有明確的屬性值!

          一個(gè)類可能需要在構(gòu)造函數(shù)內(nèi)動(dòng)態(tài)分配資源,那么這些動(dòng)態(tài)開辟的資源就需要在對(duì)象不復(fù)存在之前被銷毀掉,那么c++類的析構(gòu)函數(shù)就提供了這個(gè)方便。

          3)構(gòu)造函數(shù)的初始化表

          構(gòu)造函數(shù)有個(gè)特殊的初始化方式叫“初始化表達(dá)式表”(簡(jiǎn)稱初始化表)。初始化表位于函數(shù)參數(shù)表之后,卻在函數(shù)體 {} 之前。這說明該表里的初始化工作發(fā)生在函數(shù)體內(nèi)的任何代碼被執(zhí)行之前。

          構(gòu)造函數(shù)初始化表的使用規(guī)則:

          <1> 如果類存在繼承關(guān)系,派生類必須在其初始化表里調(diào)用基類的構(gòu)造函數(shù)。例如:

          class A

          {  

              A(int x); // A 的構(gòu)造函數(shù)

          };

          class B : public A

          {  

              B(int x, int y);// B 的構(gòu)造函數(shù)

          };

          B::B(int x, int y): A(x) // 在初始化表里調(diào)用A 的構(gòu)造函數(shù)

          {  

          }

          <2>類的 const 常量只能在初始化表里被初始化,因?yàn)樗荒茉诤瘮?shù)體內(nèi)用賦值的方式來初始化。

          <3>類的數(shù)據(jù)成員的初始化可以采用初始化表或函數(shù)體內(nèi)賦值兩種方式,這兩種方式的效率不完全相同。

          [1]非內(nèi)部數(shù)據(jù)類型的成員對(duì)象應(yīng)當(dāng)采用第一種方式初始化,以獲取更高的效率。例如:

          class A

          {  

              A(void); // 無參數(shù)構(gòu)造函數(shù)

              A(const A &other); // 拷貝構(gòu)造函數(shù)

              A & operate =( const A &other); // 賦值函數(shù)

          }

          class B

          {

          public:  

              B(const A &a); // B 的構(gòu)造函數(shù) 

          private: 

              A m_a; // 成員對(duì)象

          };

          示例 9-2(a)中,類B 的構(gòu)造函數(shù)在其初始化表里調(diào)用了類A的拷貝構(gòu)造函數(shù),從而將成員對(duì)象m_a 初始化。

          示例 9-2 (b)中,類B 的構(gòu)造函數(shù)在函數(shù)體內(nèi)用賦值的方式將成員對(duì)象m_a 初始化。我們看到的只是一條賦值語句,但實(shí)際上B 的構(gòu)造函數(shù)干了兩件事:先暗地里創(chuàng)建m_a對(duì)象(調(diào)用了A 的無參數(shù)構(gòu)造函數(shù)),再調(diào)用類A 的賦值函數(shù),將參數(shù)a 賦給m_a

          示例 9-2(a) 成員對(duì)象在初始化表中被初始化:

          B::B(const A &a) : m_a(a)

          {  

             

          }

          示例9-2(b) 成員對(duì)象在函數(shù)體內(nèi)被初始化:

          B::B(const A &a)

          {      

              m_a = a;

               

          }

          [2]對(duì)于內(nèi)部數(shù)據(jù)類型的數(shù)據(jù)成員而言,兩種初始化方式的效率幾乎沒有區(qū)別,但后者的程序版式似乎更清晰些。若類F的聲明如下:

          class F

          {    

          public:  

              F(int x, int y); // 構(gòu)造函數(shù)

          private:          

              int m_x, m_y;  

              int m_i, m_j;

          }

          示例9-2(c)F 的構(gòu)造函數(shù)采用了第一種初始化方式,示例9-2(d)F 的構(gòu)造函數(shù)采用了第二種初始化方式。

          示例 9-2(c) 數(shù)據(jù)成員在初始化表中被初始化:

          F::F(int x, int y) : m_x(x), m_y(y)

          {

              m_i = 0;

              m_j = 0;

          }

          示例9-2(d) 數(shù)據(jù)成員在函數(shù)體內(nèi)被初始化

          F::F(int x, int y)

          {     

              m_x = x;

              m_y = y; 

              m_i = 0;   

              m_j = 0;

          }

          (4)拷貝構(gòu)造函數(shù)和賦值函數(shù)的區(qū)別

          拷貝構(gòu)造函數(shù)和賦值函數(shù)非常容易混淆,常導(dǎo)致錯(cuò)寫、錯(cuò)用。拷貝構(gòu)造函數(shù)是在對(duì)象被創(chuàng)建時(shí)調(diào)用的,而賦值函數(shù)只能被已經(jīng)存在了的對(duì)象調(diào)用。以下程序中,第三個(gè)語句和第四個(gè)語句很相似,你分得清楚哪個(gè)調(diào)用了拷貝構(gòu)造函數(shù),哪個(gè)調(diào)用了賦值函數(shù)嗎?

          String a(hello);

          String b(world);

          String c = a; // 調(diào)用了拷貝構(gòu)造函數(shù),最好寫成c(a);

          c = b; // 調(diào)用了賦值函數(shù)

          5)析構(gòu)函數(shù)也是特殊的類成員函數(shù),它沒有返回類型,沒有參數(shù),不能隨意調(diào)用,也沒有重載,只有在類對(duì)象的生命期結(jié)束的時(shí)候,由系統(tǒng)自動(dòng)調(diào)用,用來在系統(tǒng)釋放對(duì)象前做一些清理工作,如利用delete運(yùn)算符釋放臨時(shí)分配的內(nèi)存、清零某些內(nèi)存單元等。

          定義析構(gòu)函數(shù)因使用"~"符號(hào)加類名(邏輯非運(yùn)算符),表示它為逆構(gòu)造函數(shù),它不能帶任何參數(shù)。

          參考:

          C和指針》

          《高質(zhì)量C++編程指南》

          C++拷貝構(gòu)造函數(shù)(深拷貝,淺拷貝)http://hi.baidu.com/onlinewan/blog/item/df0a8c189879e2b44aedbc73.html

           

          主站蜘蛛池模板: 甘孜| 吴忠市| 谷城县| 张家港市| 广德县| 二手房| 长乐市| 伊宁县| 交城县| 玉环县| 周口市| 荆州市| 略阳县| 金秀| 达尔| 子长县| 楚雄市| 靖西县| 华安县| 互助| 綦江县| 韶关市| 临海市| 莎车县| 南阳市| 鲜城| 绿春县| 河源市| 鄂尔多斯市| 读书| 滕州市| 民勤县| 鸡西市| 忻城县| 杂多县| 香港| 正镶白旗| 长沙市| 东乡县| 张家界市| 桃源县|