青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

woaidongmao

文章均收錄自他人博客,但不喜標(biāo)題前加-[轉(zhuǎn)貼],因其丑陋,見(jiàn)諒!~
隨筆 - 1469, 文章 - 0, 評(píng)論 - 661, 引用 - 0
數(shù)據(jù)加載中……

論C++構(gòu)造函數(shù)中的不合理設(shè)計(jì)

  在C++中,構(gòu)造函數(shù)是一個(gè)在構(gòu)件對(duì)象的時(shí)候調(diào)用的特殊的函數(shù),其目的是對(duì)對(duì)象進(jìn)行初始化的工作,從而使對(duì)象被使用之前可以處于一種合理的狀態(tài)。但是,構(gòu)造函數(shù)的設(shè)計(jì)并不完美,甚至有些不合理的特性。比如說(shuō),限定構(gòu)造函數(shù)名稱與類的名稱相同的條件。這些特性在構(gòu)造C++編譯器的時(shí)候是值得引起注意的。還有,在今后C++的標(biāo)準(zhǔn)修訂或者制定其他面向?qū)ο蟮脑O(shè)計(jì)語(yǔ)言時(shí)候應(yīng)當(dāng)避免這些特性。這里也提出了一些解決的方案。
  C++中,任何類都有一個(gè)(至少有一個(gè))構(gòu)造函數(shù),甚至在沒(méi)有構(gòu)造函數(shù)被聲明的時(shí)候亦是如此。在對(duì)象被聲明的時(shí)候,或者被動(dòng)態(tài)生成的時(shí)候,這些構(gòu)造函數(shù)就會(huì)被調(diào)用。構(gòu)造函數(shù)做了許多不可見(jiàn)的工作,即使構(gòu)造函數(shù)中沒(méi)有任何代碼,這些工作包括對(duì)對(duì)象的內(nèi)存分配和通過(guò)賦值的方式對(duì)成員進(jìn)行初始化。構(gòu)造函數(shù)的名稱必須與類的名稱相同,但是可以有許多不同的重載版本來(lái)提供,通過(guò)參數(shù)類型來(lái)區(qū)分構(gòu)造函數(shù)的版本。構(gòu)造函數(shù)可以顯式的通過(guò)用戶代碼來(lái)調(diào)用,或者當(dāng)代碼不存在是通過(guò)編譯程序來(lái)隱式插入。當(dāng)然,顯式地通過(guò)代碼調(diào)用是推薦的方法,因?yàn)殡[式調(diào)用的效果可能不是我們所預(yù)料的,特別是在處理動(dòng)態(tài)內(nèi)存分配方面。代碼通過(guò)參數(shù)來(lái)調(diào)用唯一的構(gòu)造函數(shù)。構(gòu)造函數(shù)沒(méi)有返回值,盡管在函數(shù)體中可以又返回語(yǔ)句。每個(gè)構(gòu)造函數(shù)可以以不同的方式來(lái)實(shí)例化一個(gè)對(duì)象,因?yàn)槊總€(gè)類都有構(gòu)造函數(shù),至少也是缺省構(gòu)造函數(shù),所以每個(gè)對(duì)象在使用之前都相應(yīng)的使用構(gòu)造函數(shù)。構(gòu)造函數(shù)的調(diào)用如圖1所示。

  因?yàn)闃?gòu)造函數(shù)是一種函數(shù),所以他的可見(jiàn)性無(wú)非是三種public、private、protected。通常,構(gòu)造函數(shù)都被聲明為public型。如果構(gòu)造函數(shù)被聲明為private或protected,就限制了對(duì)象的實(shí)例化。這在阻止類被其他人實(shí)例化的方面很有效。構(gòu)造函數(shù)中可以有任何C++的語(yǔ)句,比如,一條打印語(yǔ)句,可以被加入到構(gòu)造函數(shù)中來(lái)表明調(diào)用的位置。

 


構(gòu)造函數(shù)的類型

  C++中構(gòu)造函數(shù)有許多種類型,最常用的式缺省構(gòu)造函數(shù)和拷貝構(gòu)造函數(shù),也存在一些不常用的構(gòu)造函數(shù)。下面介紹了四種不同的構(gòu)造函數(shù)。

1、缺省構(gòu)造函數(shù)
  缺省構(gòu)造函數(shù)是沒(méi)有參數(shù)的函數(shù)。另外,缺省構(gòu)造函數(shù)也可以在參數(shù)列表中以參數(shù)缺省值的方式聲明。缺省構(gòu)造函數(shù)的作用是把對(duì)象初始化為缺省的狀態(tài)。如果在類中沒(méi)有顯式定義構(gòu)造函數(shù),那么編譯器會(huì)自動(dòng)的隱式創(chuàng)建一個(gè),這個(gè)隱式創(chuàng)建的構(gòu)造函數(shù)和一個(gè)空的構(gòu)造函數(shù)很相像。他除了產(chǎn)生對(duì)象的實(shí)例以外什么工作都不做。在許多情況下,缺省構(gòu)造函數(shù)都會(huì)被自動(dòng)的調(diào)用,例如在一個(gè)對(duì)象被聲明的時(shí)候,就會(huì)引起缺省構(gòu)造函數(shù)的調(diào)用。

2、拷貝構(gòu)造函數(shù)
  拷貝構(gòu)造函數(shù),經(jīng)常被稱作X(X&),是一種特殊的構(gòu)造函數(shù),他由編譯器調(diào)用來(lái)完成一些基于同一類的其他對(duì)象的構(gòu)件及初始化。它的唯一的一個(gè)參數(shù)(對(duì)象的引用)是不可變的(因?yàn)槭莄onst型的)。這個(gè)函數(shù)經(jīng)常用在函數(shù)調(diào)用期間于用戶定義類型的值傳遞及返回。拷貝構(gòu)造函數(shù)要調(diào)用基類的拷貝構(gòu)造函數(shù)和成員函數(shù)。如果可以的話,它將用常量方式調(diào)用,另外,也可以用非常量方式調(diào)用。
  在C++中,下面三種對(duì)象需要拷貝的情況。因此,拷貝構(gòu)造函數(shù)將會(huì)被調(diào)用。
  1). 一個(gè)對(duì)象以值傳遞的方式傳入函數(shù)體
  2). 一個(gè)對(duì)象以值傳遞的方式從函數(shù)返回
  3). 一個(gè)對(duì)象需要通過(guò)另外一個(gè)對(duì)象進(jìn)行初始化
  以上的情況需要拷貝構(gòu)造函數(shù)的調(diào)用。如果在前兩種情況不使用拷貝構(gòu)造函數(shù)的時(shí)候,就會(huì)導(dǎo)致一個(gè)指針指向已經(jīng)被刪除的內(nèi)存空間。對(duì)于第三種情況來(lái)說(shuō),初始化和賦值的不同含義是構(gòu)造函數(shù)調(diào)用的原因。事實(shí)上,拷貝構(gòu)造函數(shù)是由普通構(gòu)造函數(shù)和賦值操作賦共同實(shí)現(xiàn)的。描述拷貝構(gòu)造函數(shù)和賦值運(yùn)算符的異同的參考資料有很多。
  拷貝構(gòu)造函數(shù)不可以改變它所引用的對(duì)象,其原因如下:當(dāng)一個(gè)對(duì)象以傳遞值的方式傳一個(gè)函數(shù)的時(shí)候,拷貝構(gòu)造函數(shù)自動(dòng)的被調(diào)用來(lái)生成函數(shù)中的對(duì)象。如果一個(gè)對(duì)象是被傳入自己的拷貝構(gòu)造函數(shù),它的拷貝構(gòu)造函數(shù)將會(huì)被調(diào)用來(lái)拷貝這個(gè)對(duì)象這樣復(fù)制才可以傳入它自己的拷貝構(gòu)造函數(shù),這會(huì)導(dǎo)致無(wú)限循環(huán)。
  除了當(dāng)對(duì)象傳入函數(shù)的時(shí)候被隱式調(diào)用以外,拷貝構(gòu)造函數(shù)在對(duì)象被函數(shù)返回的時(shí)候也同樣的被調(diào)用。換句話說(shuō),你從函數(shù)返回得到的只是對(duì)象的一份拷貝。但是同樣的,拷貝構(gòu)造函數(shù)被正確的調(diào)用了,你不必?fù)?dān)心。
  如果在類中沒(méi)有顯式的聲明一個(gè)拷貝構(gòu)造函數(shù),那么,編譯器會(huì)私下里為你制定一個(gè)函數(shù)來(lái)進(jìn)行對(duì)象之間的位拷貝(bitwise copy)。這個(gè)隱含的拷貝構(gòu)造函數(shù)簡(jiǎn)單的關(guān)聯(lián)了所有的類成員。許多作者都會(huì)提及這個(gè)默認(rèn)的拷貝構(gòu)造函數(shù)。注意到這個(gè)隱式的拷貝構(gòu)造函數(shù)和顯式聲明的拷貝構(gòu)造函數(shù)的不同在于對(duì)于成員的關(guān)聯(lián)方式。顯式聲明的拷貝構(gòu)造函數(shù)關(guān)聯(lián)的只是被實(shí)例化的類成員的缺省構(gòu)造函數(shù)除非另外一個(gè)構(gòu)造函數(shù)在類初始化或者在構(gòu)造列表的時(shí)候被調(diào)用。
  拷貝構(gòu)造函數(shù)是程序更加有效率,因?yàn)樗挥迷贅?gòu)造一個(gè)對(duì)象的時(shí)候改變構(gòu)造函數(shù)的參數(shù)列表。設(shè)計(jì)拷貝構(gòu)造函數(shù)是一個(gè)良好的風(fēng)格,即使是編譯系統(tǒng)提供的幫助你申請(qǐng)內(nèi)存默認(rèn)拷貝構(gòu)造函數(shù)。事實(shí)上,默認(rèn)拷貝構(gòu)造函數(shù)可以應(yīng)付許多情況。

3、用戶定義的構(gòu)造函數(shù)
  用戶定義的構(gòu)造函數(shù)允許對(duì)象在被定義的時(shí)候同時(shí)被初始化。這種構(gòu)造函數(shù)可以有任何類型的參數(shù)。一個(gè)用戶定義的和其它類型的構(gòu)造函數(shù)在類 mystring 中得以體現(xiàn):

  class mystring
  {......
  public: mystring(); // Default constructor
  mystring (mystring &src)
  // Copy constructor
  mystring (char * scr);
  // Coercion constructor
  mystring ( char scr[ ], size_t len);
  // User-Defined constructor

  };


4、強(qiáng)制構(gòu)造函數(shù)
  C++中,可以聲明一個(gè)只有一個(gè)參數(shù)的構(gòu)造函數(shù)來(lái)進(jìn)行類型轉(zhuǎn)換。強(qiáng)制構(gòu)造函數(shù)定一個(gè)從參數(shù)類型進(jìn)行的一個(gè)類型轉(zhuǎn)換(隱式的或顯式的)。換句話說(shuō),編譯器可以用任何參數(shù)的實(shí)例來(lái)調(diào)用構(gòu)造函數(shù)。這樣做的目的是建立一個(gè)臨時(shí)實(shí)例來(lái)替換一個(gè)參數(shù)類型的實(shí)例。注意標(biāo)準(zhǔn)新近加入C++的關(guān)鍵字explicit 是用來(lái)禁止隱式的類型轉(zhuǎn)換。然而,這一特性還沒(méi)能被所有的編譯器支持。下面是一個(gè)強(qiáng)制構(gòu)造函數(shù)的例子:


  class A
  {
  public :
  A(int ){ }
  };
  void f(A) { }
  void g()
  {
  A My_Object= 17;
  A a2 = A(57);
  A a3(64);
  My_Object = 67;
  f(77);
  }

  像A My_Object= 17;這種聲明意味著A(int)構(gòu)造函數(shù)被調(diào)用來(lái)從整型變量生成一個(gè)對(duì)象。這樣的構(gòu)造函數(shù)就是強(qiáng)制構(gòu)造函數(shù)。


普遍特性

  下面是一些C++構(gòu)造函數(shù)的不合理設(shè)計(jì),當(dāng)然,可能還有其他一些不合理之處。但是,大多數(shù)情況下,我們還是要和這些特性打交道,我們要逐一說(shuō)明。

1、構(gòu)造函數(shù)可以為內(nèi)聯(lián),但不要這樣做
  一般來(lái)講,大多數(shù)成員函數(shù)都可以在前面加入"inline"關(guān)鍵字而成為內(nèi)聯(lián)函數(shù),構(gòu)造函數(shù)也不例外,但是別這么做!一個(gè)被定義為內(nèi)聯(lián)的構(gòu)造函數(shù)如下:

  class x
  {..........
  public : x (int );
  :
  :
  };
  inline x::x(int )
  {...}

  在上面的代碼中,函數(shù)并不是作為一個(gè)單獨(dú)的實(shí)體而是被插入到程序代碼中。這對(duì)于只有一兩條語(yǔ)句的函數(shù)來(lái)說(shuō)會(huì)提到效率,因?yàn)檫@里沒(méi)有調(diào)用函數(shù)的開(kāi)銷。
  用內(nèi)聯(lián)的構(gòu)造函數(shù)的危險(xiǎn)性可以在定義一個(gè)靜態(tài)內(nèi)聯(lián)構(gòu)造函數(shù)中體現(xiàn)。在這種情況下,靜態(tài)的構(gòu)造函數(shù)應(yīng)當(dāng)是只被調(diào)用一次。然而,如果頭文件中含有靜態(tài)內(nèi)聯(lián)構(gòu)造函數(shù),并被其他單元包括的話,函數(shù)就會(huì)產(chǎn)生多次拷貝。這樣,在程序啟動(dòng)時(shí)就會(huì)調(diào)用所有的函數(shù)拷貝,而不是程序應(yīng)當(dāng)調(diào)用的一份拷貝。這其中的根本原因是靜態(tài)函數(shù)是在以函數(shù)偽裝下的真實(shí)對(duì)象。
  應(yīng)該牢記的一件事是內(nèi)聯(lián)是建議而不是強(qiáng)制,編譯器產(chǎn)生內(nèi)聯(lián)代碼。這意味著內(nèi)聯(lián)是與實(shí)現(xiàn)有關(guān)的編譯器的不同可能帶來(lái)很多差異。另一方面,內(nèi)聯(lián)函數(shù)中可能包括比代碼更多的東西。構(gòu)造函數(shù)被聲明為內(nèi)聯(lián),所有包含對(duì)象的構(gòu)造函數(shù)和基類的構(gòu)造函數(shù)都需要被調(diào)用。這些調(diào)用是隱含在構(gòu)造函數(shù)中的。這可能會(huì)創(chuàng)建很大的內(nèi)聯(lián)函數(shù)段,所以,不推薦使用內(nèi)聯(lián)的構(gòu)造函數(shù)。

2、構(gòu)造函數(shù)沒(méi)有任何返回類型
  對(duì)一個(gè)構(gòu)造函數(shù)指定一個(gè)返回類型是一個(gè)錯(cuò)誤,因?yàn)檫@樣會(huì)引入構(gòu)造函數(shù)的地址。這意味著將無(wú)法處理出錯(cuò)。這樣,一個(gè)構(gòu)造函數(shù)是否成功的創(chuàng)建一個(gè)對(duì)象將不可以通過(guò)返回之來(lái)確定。事實(shí)上,盡管C++的構(gòu)造函數(shù)不可以返回,也有一個(gè)方法來(lái)確定是否內(nèi)存分配成功地進(jìn)行。這種方法是內(nèi)建在語(yǔ)言內(nèi)部來(lái)處理緊急情況的機(jī)制。一個(gè)預(yù)定好的函數(shù)指針 new-handler,它可以被設(shè)置為用戶定制的對(duì)付new操作符失敗的函數(shù),這個(gè)函數(shù)可以進(jìn)行任何的動(dòng)作,包括設(shè)置錯(cuò)誤標(biāo)志、重新申請(qǐng)內(nèi)存、退出程序或者拋出異常。你可以安心的使用系統(tǒng)內(nèi)建的new-handler。最好的使構(gòu)造函數(shù)發(fā)出出錯(cuò)信號(hào)的方法,就是拋出異常。在構(gòu)造函數(shù)中拋出異常將清除錯(cuò)誤之前創(chuàng)建的任何對(duì)象及分配的內(nèi)存。
  如果構(gòu)造函數(shù)失敗而使用異常處理的話,那么,在另一個(gè)函數(shù)中進(jìn)行初始化可能是一個(gè)更好的主意。這樣,程序員就可以安全的構(gòu)件對(duì)象并得到一個(gè)合理的指針。然后,初始化函數(shù)被調(diào)用。如果初始化失敗的話,對(duì)象直接被清除。

3、構(gòu)造函數(shù)不可以被聲明為static
  C++中,每一個(gè)類的對(duì)象都擁有類數(shù)據(jù)成員的一份拷貝。但是,靜態(tài)成員則沒(méi)有這樣而是所有的對(duì)象共享一個(gè)靜態(tài)成員。靜態(tài)函數(shù)是作用于類的操作,而不是作用在對(duì)象上。可以用類名和作用控制操作符來(lái)調(diào)用一個(gè)靜態(tài)函數(shù)。這其中的一個(gè)例外就是構(gòu)造函數(shù),因?yàn)樗`反了面向?qū)ο蟮母拍睢?br>  關(guān)于這些的一個(gè)相似的現(xiàn)象是靜態(tài)對(duì)象,靜態(tài)對(duì)象的初始化是在程序的一開(kāi)始階段就進(jìn)行的(在main()函數(shù)之前)。下面的代碼解釋了這種情況。

  MyClass static_object(88, 91);

  void bar()
  {
  if (static_object.count( ) > 14) {
  ...
  }
  }

  在這個(gè)例子中,靜態(tài)變量在一開(kāi)始的時(shí)候就被初始化。通常這些對(duì)象由兩部分構(gòu)成。第一部分是數(shù)據(jù)段,靜態(tài)變量被讀取到全局的數(shù)據(jù)段中。第二部分是靜態(tài)的初始化函數(shù),在main()函數(shù)之前被調(diào)用。我們發(fā)現(xiàn),一些編譯器沒(méi)有對(duì)初始化的可靠性進(jìn)行檢查。所以你得到的是未經(jīng)初始化的對(duì)象。解決的方案是,寫(xiě)一個(gè)封裝函數(shù),將所有的靜態(tài)對(duì)象的引用都置于這個(gè)函數(shù)的調(diào)用中,上面的例子應(yīng)當(dāng)這樣改寫(xiě)。

  static MyClass* static_object = 0;

  MyClass*
  getStaticObject()
  {
  if (!static_object)
  static_object =
  new MyClass(87, 92);
  return static_object;
  }

  void bar()
  {
  if (getStaticObject()->count( ) > 15)
  {
  ...
  }
  }


4、構(gòu)造函數(shù)不能成為虛函數(shù)
  虛構(gòu)造函數(shù)意味著程序員在運(yùn)行之前可以在不知道對(duì)象的準(zhǔn)確類型的情況下創(chuàng)建對(duì)象。虛構(gòu)造函數(shù)在C++中是不可能實(shí)現(xiàn)的。最通常遇到這種情況的地方是在對(duì)象上實(shí)現(xiàn)I/O的時(shí)候。即使足夠的類的內(nèi)部信息在文件中給出,也必須找到一種方法實(shí)例化相應(yīng)的類。然而,有經(jīng)驗(yàn)的C++程序員會(huì)有其他的辦法來(lái)模擬虛構(gòu)造函數(shù)。
  模擬虛函數(shù)需要在創(chuàng)建對(duì)象的時(shí)候指定調(diào)用的構(gòu)造函數(shù),標(biāo)準(zhǔn)的方法是調(diào)用虛的成員函數(shù)。很不幸,C++在語(yǔ)法上不支持虛構(gòu)造函數(shù)。為了繞過(guò)這個(gè)限制,一些現(xiàn)成的方法可以在運(yùn)行時(shí)刻確定構(gòu)件的對(duì)象。這些等同于虛構(gòu)造函數(shù),但是這是C++中根本不存在的東西。
  第一個(gè)方法是用switch或者if-else選擇語(yǔ)句來(lái)手動(dòng)實(shí)現(xiàn)選擇。在下面的例子中,選擇是基于標(biāo)準(zhǔn)庫(kù)的type_info構(gòu)造,通過(guò)打開(kāi)運(yùn)行時(shí)刻類型信息支持。但是你也可以通過(guò)虛函數(shù)來(lái)實(shí)現(xiàn)RTTI

  class Base
  {
  public:
  virtual const char* get_type_id() const;
  staticBase* make_object
  (const char* type_name);
  };

  const char* Base::get_type_id() const
  {
  return typeid(*this).raw_name();
  }

  class Child1: public Base
  {
  };

  class Child2: public Base
  {
  };

  Base* Base::make_object(const char* type_name)
  {
  if (strcmp(type_name,
  typeid(Child1).raw_name()) == 0)
    return new Child1;
  else if (strcmp(type_name,typeid
    (Child2).raw_name()) == 0)
  return new Child2;
  else
  {
   throw exception
  ("unrecognized type name passed");
  return 0X00; // represent NULL
    }
  }
  
  這一實(shí)現(xiàn)是非常直接的,它需要程序員在main_object中保存一個(gè)所有類的表。這就破壞了基類的封裝性,因?yàn)榛惐仨氈雷约旱淖宇悺?br>  一個(gè)更面向?qū)ο蟮姆椒惤鉀Q虛構(gòu)造函數(shù)叫做標(biāo)本實(shí)例。它的基本思想是程序中生成一些全局的實(shí)例。這些實(shí)例只再虛構(gòu)造函數(shù)的機(jī)制中存在:

  class Base
  {
  public:
    staticBase* make_object(const char* typename)
  {
   if (!exemplars.empty())
   {
    Base* end = *(exemplars.end());
    list<Base*>::iterator iter =
    exemplars.begin();
    while (*iter != end)
     {
      Base* e = *iter++;
      if (strcmp(typename,
        e->get_typename()) == 0)
        return e->clone();
     }
   }
    return 0X00 // Represent NULL;
  }
  virtual ~Base() { };
  virtual const char* get_typename() const
  {
   return typeid(*this).raw_name();
  }
  virtual Base* clone() const = 0;
  protected:
  static list<Base*> exemplars;
  };
  list<Base*> Base::exemplars;
  // T must be a concrete class
  // derived from Base, above
  template<class T>
  class exemplar: public T
  {
   public:
   exemplar()
   {
    exemplars.push_back(this);
   }
  ~exemplar()
   {
   exemplars.remove(this);
   }
  };
  class Child: public Base
  {
   public:
   ~Child()
    {
    }
   Base* clone() const
   {
    return new Child;
   }
  };
  exemplar<Child> Child_exemplar;

  在這種設(shè)計(jì)中,程序員要?jiǎng)?chuàng)建一個(gè)類的時(shí)候要做的是創(chuàng)建一個(gè)相應(yīng)的exampler<T>類。注意到在這個(gè)例子中,標(biāo)本是自己的標(biāo)本類的實(shí)例。這提供了一種高校得實(shí)例化方法。

5、創(chuàng)建一個(gè)缺省構(gòu)造函數(shù)
  當(dāng)繼承被使用的時(shí)候,卻省構(gòu)造函數(shù)就會(huì)被調(diào)用。更明確地說(shuō),當(dāng)繼承層次的最晚層的類被構(gòu)造的時(shí)候,所有基類的構(gòu)造函數(shù)都在派生基類之前被調(diào)用,舉個(gè)例子來(lái)說(shuō),看下面的代碼:

  #include<iostream.h>
  class Base
  {
   int x;
   public :
      Base() : x(0) { } // The NULL constructor
      Base(int a) : x(a) { }
  };
  class alpha : virtual public Base
   {
   int y;
   public :
   alpha(int a) : Base(a), y(2) { }
   };
  class beta : virtual public Base
   {
   int z;
   public :
   beta(int a) : Base(a), z(3) { }
   };
  class gamma : public alpha, public beta
   {
    int w;
    public :
       gamma ( int a, int b) : alpha(a), beta(b), w(4) { }
   };
  main()
  {.....
  }


  在這個(gè)例子中,我們沒(méi)有在gamma的頭文件中提供任何的初始化函數(shù)。編譯器會(huì)為基類使用缺省的構(gòu)造函數(shù)。但是因?yàn)槟闾峁┝艘粋€(gè)構(gòu)造函數(shù),編譯器就不會(huì)提供任何缺省構(gòu)造函數(shù)。正如你看到的這段包含缺省構(gòu)造函數(shù)的代碼一樣,如果刪除其中的缺省構(gòu)造函數(shù),編譯就無(wú)法通過(guò)。
  如果基類的構(gòu)造函數(shù)中引入一些副效應(yīng)的話,比如說(shuō)打開(kāi)文件或者申請(qǐng)內(nèi)存,這樣程序員就得確保中間基類沒(méi)有初始化虛基類。也就是,只有虛基類的構(gòu)造函數(shù)可以被調(diào)用。
  虛基類的卻省構(gòu)造函數(shù)完成一些不需要任何依賴于派生類的參數(shù)的初始化。你加入一個(gè)init()函數(shù),然后再?gòu)奶摶惖钠渌瘮?shù)中調(diào)用它,或在其他類中的構(gòu)造函數(shù)里調(diào)用(你的確保它只調(diào)用了一次)。


6、不能取得構(gòu)造函數(shù)的地址
  C++中,不能把構(gòu)造函數(shù)當(dāng)作函數(shù)指針來(lái)進(jìn)行傳遞,指向構(gòu)造函數(shù)的的指針也不可以直接傳遞。允許這些就可以通過(guò)調(diào)用指針來(lái)創(chuàng)建對(duì)象。一種達(dá)到這種目的的方法是借助于一個(gè)創(chuàng)建并返回新對(duì)象的靜態(tài)函數(shù)。指向這樣的函數(shù)的指針用于新對(duì)象需要的地方。下面是一個(gè)例子:

  class A
  {
   public:
    A( ); // cannot take the address of this
       // constructor directly
   static A* createA();
     // This function creates a new A object
     // on the heap and returns a pointer to it.
     // A pointer to this function can be passed
     // in lieu of a pointer to the constructor.
  };

  這一方法設(shè)計(jì)簡(jiǎn)單,只需要將抽象類置入頭文件即可。這給new留下了一個(gè)問(wèn)題,因?yàn)闇?zhǔn)確的類型必須是可見(jiàn)的。上面的靜態(tài)函數(shù)可以用來(lái)包裝隱藏子類。

7、位拷貝在動(dòng)態(tài)申請(qǐng)內(nèi)存的類中不可行
  C++中,如果沒(méi)有提供一個(gè)拷貝構(gòu)造函數(shù),編譯器會(huì)自動(dòng)生成一個(gè)。生成的這個(gè)拷貝構(gòu)造函數(shù)對(duì)對(duì)象的實(shí)例進(jìn)行位拷貝。這對(duì)沒(méi)有指針成員的類來(lái)說(shuō)沒(méi)什么,但是,對(duì)用了動(dòng)態(tài)申請(qǐng)的類就不是這樣的了。為了澄清這一點(diǎn),設(shè)想一個(gè)對(duì)象以值傳遞的方式傳入一個(gè)函數(shù),或者從函數(shù)中返回,對(duì)象是以為拷貝的方式復(fù)制。這種位拷貝對(duì)含有指向其他對(duì)象指針的類是沒(méi)有作用的(見(jiàn)圖2)。當(dāng)一個(gè)含有指針的類以值傳遞的方式傳入函數(shù)的時(shí)候,對(duì)象被復(fù)制,包括指針的地址,還有,新的對(duì)象的作用域是這個(gè)函數(shù)。在函數(shù)結(jié)束的時(shí)候,很不幸,析構(gòu)函數(shù)要破壞這個(gè)對(duì)象。因此,對(duì)象的指針被刪除了。這導(dǎo)致原來(lái)的對(duì)象的指針指向一塊空的內(nèi)存區(qū)域-一個(gè)錯(cuò)誤。在函數(shù)返回的時(shí)候,也有類似的情況發(fā)生。

 


  這個(gè)問(wèn)題可以簡(jiǎn)單的通過(guò)在類中定義一個(gè)含有內(nèi)存申請(qǐng)的拷貝構(gòu)造函數(shù)來(lái)解決,這種靠叫做深拷貝,是在堆中分配內(nèi)存給各個(gè)對(duì)象的。


8、編譯器可以隱式指定強(qiáng)制構(gòu)造函數(shù)
  因?yàn)榫幾g器可以隱式選擇強(qiáng)制構(gòu)造函數(shù),你就失去了調(diào)用函數(shù)的選擇權(quán)。如果需要控制的話,不要聲明只有一個(gè)參數(shù)的構(gòu)造函數(shù),取而代之,定義helper函數(shù)來(lái)負(fù)責(zé)轉(zhuǎn)換,如下面的例子:

  #include <stdio.h>
  #include <stdlib.h>
  class Money
  {
   public:
      Money();
      // Define conversion functions that can only be
      // called explicitly.
      static Money Convert( char * ch )
      { return Money( ch ); }
      static Money Convert( double d )
      { return Money( d ); }
      void Print() { printf( "\n%f", _amount ); }
   private:
      Money( char *ch ) { _amount = atof( ch ); }
      Money( double d ) { _amount = d; }
      double _amount;

   };

  void main()
  {
   // Perform a conversion from type char *
   // to type Money.
   Money Account = Money::Convert( "57.29" );
   Account.Print();
   // Perform a conversion from type double to type
   // Money.
   Account = Money::Convert( 33.29 );
   Account.Print();
  }
  在上面的代碼中,強(qiáng)制構(gòu)造函數(shù)定義為private而不可以被用來(lái)做類型轉(zhuǎn)換。然而,它可以被顯式的調(diào)用。因?yàn)檗D(zhuǎn)換函數(shù)是靜態(tài)的,他們可以不用引用任何一個(gè)對(duì)象來(lái)完成調(diào)用。


總結(jié)

  要澄清一點(diǎn)是,這里提到的都是我們所熟知的ANSI C++能夠接受的。許多編譯器都對(duì)ANSI C++進(jìn)行了自己的語(yǔ)法修訂。這些可能根據(jù)編譯器的不同而不同。很明顯,許多編譯器不能很好的處理這幾點(diǎn)。探索這幾點(diǎn)的緣故是引起編譯構(gòu)造的注意,也是在C++標(biāo)準(zhǔn)化的過(guò)程中移除一些瑕疵。


參考文獻(xiàn):

1. Stroustrup, Bjarne. The C++ Programming Language, 3rd ed., Addison-Wesley, Reading, MA, 1997.
2. Ellis, Margaret and Bjarne Stroustrup. The Annotated C++ Reference Manual, Addison-Wesley, Reading,   MA, 1990.
3. Stroustrup, Bjarne. The Design and Evolution of C++, Addison-Wesley, Reading, MA, 1994.
4. Murry, Robert B. C++ Strategies and Tactics, Addison-Wesley, Reading, MA, 1993.
5. Farres-Casals, J. "Proving Correctness of Constructor Implementations," Mathematical Foundations of   Computer Science 1989 Proceedings.
6. Breymann, Ulrich. Designing Components with the C++ STL, Addison-Wesley, Reading, MA,1998.
7. Lippman, Stanley and Josee LaJoie. C++ Primer, 3rd ed., Addison-Wesley, Reading, MA, 1998.
8. Skelly, C. "Getting A Handle On The New-Handler," C++ Report, 4(2):1-18, February 1992.
9. Coggins, J. M. "Handling Failed Constructors Gracefully," C++ Report, 4(1):20-22, January 1992.
10. Sabatella, M. "Laser Evaluation of C++ Static Constructors," SIGPLAN Notices, 27(6):29-36 (June     1992).
11. Eckel, B. "Virtual Constructors," C++ Report, 4(4):13-16,May 1992.
12. Coplien, James O. Advanced C++: Programming Styles and Idioms, Addison-Wesley, Reading, MA, 1992.

posted on 2008-07-16 13:24 肥仔 閱讀(295) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++ 基礎(chǔ)

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲综合精品四区| 国产精品亚洲综合| 香蕉av福利精品导航| 黄色成人在线| 国产一区二区久久| 国产精品手机视频| 久久先锋资源| 欧美一进一出视频| 亚洲一卡久久| 亚洲区免费影片| 亚洲九九精品| 亚洲视频观看| 久久se精品一区精品二区| 久久综合五月天婷婷伊人| 久久亚洲私人国产精品va| 免费成人高清| 欧美国产精品专区| 欧美激情精品久久久久| 亚洲性感美女99在线| 亚洲免费不卡| 一区二区在线看| 欧美精品v国产精品v日韩精品 | 亚洲精品久久久一区二区三区| 亚洲人成小说网站色在线 | 国产欧美一区二区三区沐欲| 国产一区二区三区av电影| 在线看片欧美| 欧美一区亚洲二区| 欧美成人一区二区三区片免费| 极品少妇一区二区三区| 国产一区二区三区高清播放| 国产日韩在线看片| 国产有码在线一区二区视频| 亚洲精品久久久久| 欧美在线免费播放| 亚洲国产精品福利| 久久尤物视频| 精品动漫3d一区二区三区免费版| 国产日韩欧美综合| 日韩视频亚洲视频| 欧美一区二区三区视频免费播放 | 亚洲一区二区久久| 新片速递亚洲合集欧美合集| 亚洲午夜免费福利视频| 国产精品xnxxcom| 亚洲午夜视频| 亚洲视频免费在线观看| 国产精品每日更新在线播放网址| 91久久精品一区二区三区| 久久人人爽爽爽人久久久| 亚洲美女毛片| 欧美网站在线| 一本色道久久综合精品竹菊| 欧美成人午夜激情在线| 欧美在线观看网站| 欧美无乱码久久久免费午夜一区| 午夜在线精品| 香蕉精品999视频一区二区 | 亚洲精品一区二区三区樱花 | 欧美激情免费在线| 亚洲图片在线| 久久天天狠狠| 一区二区三区国产| 午夜久久久久久| 国产日韩精品久久久| 久久成人精品电影| 国产日产精品一区二区三区四区的观看方式 | 久久久久久久综合日本| 欧美一区免费| 性色av一区二区三区在线观看 | 国产欧美精品在线播放| 久久精品一区二区国产| 久久久久久电影| 亚洲一级电影| 欧美三级网页| 亚洲黄色影院| 亚洲日本精品国产第一区| 国产一区二区三区久久精品| 欧美大片18| 国产精品视频福利| 欧美高清视频在线观看| 快she精品国产999| 亚洲国产高清一区| 欧美日韩精品一区二区在线播放| 亚洲女人天堂av| 国产日产精品一区二区三区四区的观看方式| 亚洲高清在线播放| 韩国免费一区| 亚洲精品中文字幕女同| 国产亚洲美州欧州综合国| 亚洲五月六月| 国内精品久久久久影院 日本资源 国内精品久久久久伊人av | 国内精品伊人久久久久av一坑| 亚洲欧美日韩系列| 欧美调教视频| 91久久国产综合久久蜜月精品| 亚洲第一中文字幕| 国产午夜精品福利| 免费观看亚洲视频大全| 亚洲高清一区二| 亚洲国产成人av在线| 亚洲欧美三级在线| 欧美一区二区久久久| 欧美精品亚洲精品| 欧美专区日韩视频| 日韩视频中文| 老司机成人网| 亚洲区国产区| 国产精品久久久久久亚洲调教| 亚洲天堂偷拍| 久久夜色精品国产欧美乱| 亚洲一区二区黄色| 性色一区二区三区| 一区二区三区国产精品| 国产精品mm| 亚洲手机在线| 香蕉成人伊视频在线观看 | 一区二区视频欧美| 欧美精品一区二区三区高清aⅴ| 正在播放亚洲| 一区二区三区色| 噜噜噜噜噜久久久久久91| 一区二区三区高清视频在线观看| 国产美女精品视频免费观看| 欧美国产日韩一区二区三区| 欧美久久99| 在线观看一区二区精品视频| 亚洲欧美高清| 午夜影视日本亚洲欧洲精品| 亚洲区第一页| 亚洲午夜免费福利视频| **网站欧美大片在线观看| 亚洲午夜在线| 国产精品99久久久久久久久久久久| 亚洲欧美99| 一本不卡影院| 农夫在线精品视频免费观看| 久久国产免费| 国产精品人成在线观看免费| 最新高清无码专区| 激情成人在线视频| 亚洲欧美99| 亚洲欧美日韩一区二区在线 | 欧美激情中文不卡| 国产色视频一区| 亚洲欧美日韩在线一区| 国产精品xxxxx| 日韩西西人体444www| 亚洲午夜伦理| 欧美特黄a级高清免费大片a级| 亚洲欧洲精品一区二区三区| 亚洲经典自拍| 欧美伦理91i| 一本久道久久综合中文字幕 | 欧美激情亚洲视频| 亚洲精品一区中文| 一区免费观看| 久久久天天操| 亚洲电影网站| 日韩视频―中文字幕| 一本综合精品| 欧美资源在线观看| 国产日产欧美a一级在线| 欧美一区二区三区男人的天堂 | 亚洲欧洲日韩综合二区| 亚洲免费观看高清在线观看 | 欧美精品日韩一本| 夜夜嗨av一区二区三区网页| 亚洲女人天堂av| 国产欧美一区二区白浆黑人| 欧美一区在线视频| 亚洲高清视频一区| 亚洲一区在线观看视频| 国产精品久久网站| 欧美一区免费视频| 亚洲国产精品热久久| 亚洲一区在线观看视频| 国产午夜精品久久久久久免费视 | 欧美日韩一区二区三区四区在线观看 | 久久精品中文| 亚洲国产精品久久人人爱蜜臀| 欧美欧美午夜aⅴ在线观看| 亚洲免费一级电影| 亚洲高清在线播放| 国产日韩在线一区二区三区| 欧美在线视频二区| 亚洲伦理在线| 美女精品在线| 亚洲伊人第一页| 伊人久久综合| 国产精品每日更新在线播放网址| 久久国产日本精品| 一区二区三区鲁丝不卡| 麻豆freexxxx性91精品| 亚洲女人av| 一卡二卡3卡四卡高清精品视频| 国产午夜精品美女毛片视频| 免费毛片一区二区三区久久久| 亚洲欧美日本国产有色| 亚洲人成免费|