程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 拷貝構造和賦值操作符,C#和本機C++代碼的互用性(1)

拷貝構造和賦值操作符,C#和本機C++代碼的互用性(1)

編輯:關於C語言
有一個簡單的 C++ 問題。我想讓我的拷貝構造函數和賦值操作做同樣的事情。你能告訴我最佳實現方法嗎?

Shadi Hani乍一看, 這似乎是一個答案簡單的簡單問題:寫一個調用 Operator= 的構造函數不就行了:CFoo::CFoo(const CFoo& obj)
{
   *this = obj;
}

或者,寫一個公用的拷貝方法,拷貝構造函數和 Operator= 都調用這個方法也行。就像這樣:

CFoo::CFoo(const CFoo& obj)
{
  CopyObj(obj);
}
CFoo& CFoo::Operator=(const CFoo& rhs)
{
  CopyObj(rhs);
  return *this;
}

對於大多數類來說,這是行得通的,但還有些 特殊情況需要考慮。如果你的類包含有數據成員是另一個類的實例會怎樣呢?為了弄清楚這個問題,我寫了一個測試程序如 Figure 1 所示。 它有一個主類 CMainClass,它包含另一個類 CMember 的實例。兩個類都有拷貝構造函數和賦值操作,用 CMainClass 的拷貝構造函數調用 Operator=,如下面的代碼段所示。代碼中使用 printf 語句是為了顯示何時調用了哪個方法。為了運行構造函數,cctest 程序首先用缺省構 造函數創建 CMainClass 實例,然後用拷貝構造函數創建另一個實例:

CMainClass obj1;
CMainClass obj2 (obj1);

如果你編譯並運行 cctest,當構造 obj2 時,你會看到下面的 printf 信息:

CMember: default ctor
CMainClass: copy-ctor
CMainClass: Operator=
CMember: Operator=

成員對象 m_obj 被初始化了兩次!第一次是缺 省構造,第二次是賦值時再次被初始化。嘿,這是怎麼回事?

在 C++ 中,賦值和拷貝是不同的,因為拷貝構造函數是對未初始化的內 存進行初始化操作,而賦值是對現有的已經初始化的對象進行操作。如果你的類包含其它的類實例作為數據成員,那麼拷貝構造在調用 Operator=之前必須首先構造這些數據成員。其結果是致使這些成員就像 cctest 那樣被初始化兩次,明白了嗎?當你用賦值操作而不是初始化 例程進行成員初始化時,缺省構造函數也會發生同樣的事情。例如:

CFoo::CFoo()
{
  m_obj = DEFAULT;
}

與下面代碼相對:

CFoo::CFoo() : m_obj(DEFAULT)
{
}

使用賦值方式,m_obj 被初始化兩 次,而用初始化例程語法,m_obj 只被初始化一次。所以,要如何避免拷貝構造期間額外的初始化呢?當它與你的代碼重用初衷相抵觸時, 最 好的解決俄u方法就是分開實現拷貝構造和賦值操作,即便它們做同樣的事情。從拷貝構造中調用 Operator= 肯定能行得通,但不是最有效率 的實現。我對初始化的建議是:

CFoo::CFoo(const CFoo& rhs) : m_obj(rhs.m_obj) {}

現在,主拷貝構造用初 始化例程調用成員對象的拷貝構造,並且 m_obj 只被其拷貝構造初始化一次。通常情況下,拷貝構造應該調用其成員的拷貝構造。賦值也是如 此。並且,它也同樣適用於基類:派生類的拷貝構造和賦值操作應該調用對應的基類方法。當然,有時因為一些具體情況,可能你的做法會有 所不同——這裡我所描述的是通用規則,只有在你遇到強制性原因時才會破壞這個規則。如果你要在基本對象被初始化之後完成一 些公共任務,可以將它們放到一個公共的初始化方法中,並在構造函數和 Operator= 中調用。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved