消除複製建構函式和“模板式複製建構函式”中的冗餘程式碼 (轉)

worldblog發表於2008-01-21
消除複製建構函式和“模板式複製建構函式”中的冗餘程式碼 (轉)[@more@]

  寫完了《當心生成的隱含成員》一文,總是對在兩個不同的函式中使用相同的程式碼(只是引數型別不同)做相同的事耿耿於懷。在《C++ STL 中文版》中的quto_ptr中的程式碼很簡單,但很多時候我們要做的並不是這麼簡單的。程式碼冗餘的危害不只是讓你把相同的程式碼多寫一遍,而且會給你的修改帶來麻煩——你很容易修改了一個實現而忘記了另一個。賦值運算子的問題很好解決,可以簡單地用一個模板成員函式來完成實際的賦值操作,然後在你的複製賦值運算子和模板形式的賦值運算子的實現中都只是簡單地這個成員函式(就是下面的方法一);而複製建構函式就相對複雜了一些,因為出於某種理由我們可能需要在成員初始化表中對成員進行初始化而不是在程式碼中注一,而普通的成員函式是不能使用這種方法的。下面列出幾種解決方法,供大家參考:

 

  方法一:使用模板成員函式完成構造。

  就是說使用一個模板成員函式來完成需要在複製建構函式中可以放在函式體中的程式碼部分,然後在複製建構函式和“偽複製建構函式”注二的實現程式碼中都只是簡單地呼叫它。程式碼示意如下:

  template

  class smart_ptr

  {

  T* ptr_data;

  template

  void DoCopyConstruct(const smart_ptr &)

  {

  ptr_data = .get_ptr();

  //其它處理

  }

  public:

  T* get_ptr()const{return ptr_data;}

  smart_ptr(const smart_ptr& Source){DoCopyConstruct(Source);}

 

  template

  smart_ptr(const smart_ptr& Source){DoCopyConstruct(Source);}

  };

  這種方法的缺點在於:當有需要在建構函式的成員初始化列表中進行初始化的成員存在時,對這些成員的初始化仍然要在兩個建構函式的成員初始化表中各寫一遍。不過,一般情況下成員初始化表中的程式碼都很簡單,改動相對較少,所以這裡的程式碼危害也就不是很大。

 

  方法二:使用一個成員封裝資料。

  事實上,我們對一個物件進行構造實質就是對資料進行初始化,我們可以把資料用一個類封裝起來成為一個成員物件,然後在建構函式中在成員初始化表中對這個物件進行初始化。而這時我們在把“偽複製建構函式”轉移到這個資料類中時可以對它的引數型別進行修改,使它不受複製建構函式的影響,比如加一個匿名引數,更簡單的方法是把引數型別從引用改為指標。程式碼示意如下:

  template
  class data
  {
  data(const data &);//這個建構函式是不被呼叫的,寫成私有以免誤被呼叫。
  public:
  T* ptr;

  template
  data(const data * Source):
  ptr(Source->ptr)
  {
  //其它處理
  }
  };

  template
  class smart_ptr
  {
  data ptr_data;
  public:
  const data& get_data()const {return ptr_data;}

  smart_ptr(const smart_ptr& Source):ptr_data(&Source.get_data()){}
 
  template
  smart_ptr(const smart_ptr& Source):ptr_data(&Source.get_data()){}
  };

  方法三:把複製操作放到基類中實現。

  就是說,為你的類寫一個基類,在基類中寫一個不受複製建構函式影響的模板建構函式,在衍生類中呼叫這個建構函式。這種方法的原理基本上是和方法二是一樣的,只是把組合變成了繼承。程式碼示意如下:

  template
  class smart_ptr_base
  {
  smart_ptr_base(const smart_ptr_base &);//這個建構函式是不被呼叫的,寫成私有以免誤被呼叫。
  protected:
  T* ptr;
  public:

  T* get_ptr()const {return ptr}
  template
  data(const smart_ptr_base * Source):
  ptr(Source->get_ptr())
  {
  //其它處理
  }
  };

  template
  class smart_ptr: protected smart_ptr_base
  {
  public:

  smart_ptr(const smart_ptr& Source):smart_ptr_base(&Source){}
 
  template
  smart_ptr(const smart_ptr& Source):smart_ptr_base(&Source){}
  };

  上面只列出了三種方法,但我想解決一個問題的方法是很多的,一定還存在其它方法,如果大家想到了,我希望能夠to:plainsong@vip.sina.com">告訴我或補充在這裡,由衷感謝。

  此外,上面的示意程式碼只是針對本文提出的問題的,並沒有考慮其它因素,在應用時不能簡單照般,還要根據具體情況進行修改。

 

注一:這種理由可以找到很多,比如常量成員的存在、成員無預設(無引數的)建構函式、原因等。

注二:就是題目中的“模板式複製建構函式”,我實在不知道該叫它什麼名字了,也許稱作“模板式複製建構函式”更清晰一些,但容易讓人誤認為它是一個真正的複製建構函式,因此在本文中就把它稱為“偽複製建構函式”


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-997933/,如需轉載,請註明出處,否則將追究法律責任。

相關文章