在網上摘到的好內容,以備查看

來源:互聯網
上載者:User

1. c++中:符號的意思

我的問題是關於初始化C++類成員的。我見過許多這樣的代碼(包括在你的欄目中也見到過):  
  CSomeClass::CSomeClass()  
  {  
          x=0;  
          y=1;  
  }  
  而在別的什麼地方則寫成下面的樣子:  
  CSomeClass::CSomeClass()   :   x(0),   y(1)  
  {  
  }  
  我的一些程式員朋友說第二種方法比較好,但他們都不知道為什麼是這樣。你能告訴我這兩種類成員初始化方法的區別嗎?  

  回答  
   
          從技術上說,你的程式員朋友是對的,但是在大多數情況下,兩者實際上沒有區別。有兩個原因使得我們選擇第二種文法,  
  它被稱為成員初始化列表:一個原因是必須的,另一個只是出於效率考慮。  
   
          讓我們先看一下第一個原因——必要性。設想你有一個類成員,它本身是一個類或者結構,而且只有一個帶一個參數的建構函式。  
   
  class   CMember   {  
  public:  
          CMember(int   x)   {   ...   }  
  };  
          因為Cmember有一個顯式聲明的建構函式,編譯器不產生一個預設建構函式(不帶參數),所以沒有一個整數就無法建立  
  Cmember的一個執行個體。  
   
  CMember*   pm   =   new   CMember;                 //   Error!!  
  CMember*   pm   =   new   CMember(2);           //   OK  
   
   如果Cmember是另一個類的成員,你怎樣初始化它呢?你必須使用成員初始化列表。  
   
  class   CMyClass   {  
          CMember   m_member;  
  public:  
          CMyClass();  
  };  
   
  //必須使用成員初始化列表  
   
  CMyClass::CMyClass()   :   m_member(2)  
  {  
  ???  
  }  
   
       沒有其它辦法將參數傳遞給m_member,如果成員是一個常量對象或者引用也是一樣。根據C++的規則,常量對象和引用不能被賦值,它們只能被初始化。  
   
          第二個原因是出於效率考慮,當成員類具有一個預設的建構函式和一個賦值操作符時。MFC的Cstring提供了一個完美的例子。  
  假定你有一個類CmyClass具有一個Cstring類型的成員m_str,你想把它初始化為"yada   yada."。你有兩種選擇:  
   
  CMyClass::CMyClass()   {  
          //   使用賦值操作符  
          //   CString::operator=(LPCTSTR);  
          m_str   =   _T("yada   yada");  
  }  
   
  //使用類成員列表  
  //   and   constructor   CString::CString(LPCTSTR)  
  CMyClass::CMyClass()   :   m_str(_T("yada   yada"))  
  {  
  }  
   
          在它們之間有什麼不同嗎?是的。編譯器總是確保所有成員對象在建構函式體執行之前初始化,因此在第一個例子中編譯  
  的代碼將調用CString::Cstring來初始化m_str,這在控制到達指派陳述式前完成。在第二個例子中編譯器產生一個對  
  CString::   CString(LPCTSTR)的調用並將"yada   yada"傳遞給這個函數。結果是在第一個例子中調用了兩個Cstring函數  
  (建構函式和賦值操作符),而在第二個例子中只調用了一個函數。在Cstring的例子裡這是無所謂的,因為預設建構函式是  
  內聯的,Cstring只是在需要時為字串分配記憶體(即,當你實際賦值時)。但是,一般而言,重複的函數調用是浪費資源的,  
  尤其是當建構函式和賦值操作符分配記憶體的時候。在一些大的類裡面,你可能擁有一個建構函式和一個賦值操作符都要調用同  
  一個負責分配大量記憶體空間的Init函數。在這種情況下,你必須使用初始化列表,以避免不要的分配兩次記憶體。在內部類型如  
  ints或者longs或者其它沒有建構函式的類型下,在初始化列表和在建構函式體內賦值這兩種方法沒有效能上的差別。不管用那  
  一種方法,都只會有一次賦值發生。有些程式員說你應該總是用初始化列表以保持良好習慣,但我從沒有發現根據需要在這兩種  
  方法之間轉換有什麼困難。在編程風格上,我傾向於在主體中使用賦值,因為有更多的空間用來格式化和添加註釋,你可以寫出  
  這樣的語句:x=y=z=0;或者memset(this,0,sizeof(this));  
          注意第二個片斷絕對是非物件導向的。  
          當我考慮初始化列表的問題時,有一個奇怪的特性我應該警告你,它是關於C++初始化類成員的,它們是按照聲明的順序初  
  始化的,而不是按照出現在初始化列表中的順序。  
   
  class   CMyClass   {  
          CMyClass(int   x,   int   y);  
          int   m_x;  
          int   m_y;  
  };  
   
  CMyClass::CMyClass(int   i)   :   m_y(i),   m_x(m_y)  
  {  
  }  
   
  你可能以為上面的代碼將會首先做m_y=I,然後做m_x=m_y,最後它們有相同的值。但是編譯器先初始化m_x,然後是m_y,,因為  
  它們是按這樣的順序聲明的。結果是m_x將有一個不可預測的值。我的例子設計來說明這一點,然而這種bug會更加自然的出現。  
  有兩種方法避免它,一個是總是按照你希望它們被初始化的順序聲明成員,第二個是,如果你決定使用初始化列表,總是按照  
  它們聲明的順序羅列這些成員。這將有助於消除混淆。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.