消除複製建構函式和“模板式複製建構函式”中的冗餘程式碼 (轉)
寫完了《當心生成的隱含成員》一文,總是對在兩個不同的函式中使用相同的程式碼(只是引數型別不同)做相同的事耿耿於懷。在《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
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
public:
const data
smart_ptr(const smart_ptr
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
template
smart_ptr(const smart_ptr& Source):smart_ptr_base(&Source){}
};
上面只列出了三種方法,但我想解決一個問題的方法是很多的,一定還存在其它方法,如果大家想到了,我希望能夠to:plainsong@vip.sina.com">告訴我或補充在這裡,由衷感謝。
此外,上面的示意程式碼只是針對本文提出的問題的,並沒有考慮其它因素,在應用時不能簡單照般,還要根據具體情況進行修改。
注一:這種理由可以找到很多,比如常量成員的存在、成員無預設(無引數的)建構函式、原因等。
注二:就是題目中的“模板式複製建構函式”,我實在不知道該叫它什麼名字了,也許稱作“模板式複製建構函式”更清晰一些,但容易讓人誤認為它是一個真正的複製建構函式,因此在本文中就把它稱為“偽複製建構函式”
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-997933/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 預設建構函式、引數化建構函式、複製建構函式、解構函式函式
- C++複製建構函式C++函式
- C++ 移動構造和複製建構函式匹配C++函式
- 結構體中的指標&&複製賦值建構函式改造結構體指標賦值函式
- 物件的生存期 記憶體 深度複製 複製建構函式 筆記物件記憶體函式筆記
- C++ 禁用類的複製建構函式和賦值運算子C++函式賦值
- C++中建構函式,拷貝建構函式和賦值函式的詳解C++函式賦值
- 深度解讀《深度探索C++物件模型》之複製建構函式C++物件模型函式
- 類的建構函式和解構函式函式
- 建構函式與解構函式函式
- 【C/C++】為什麼需要複製建構函式的同時通常也需要過載複製運算子C++函式
- 建構函式和類函式
- ## 建構函式函式
- C++ 建構函式和解構函式C++函式
- 繼承中的建構函式繼承函式
- JavaScript 建構函式JavaScript函式
- 關於建構函式與解構函式的分享函式
- 預設建構函式和帶預設值的建構函式不能同時存在函式
- PHP筆記:建構函式與解構函式PHP筆記函式
- 建構函式與普通函式的區別函式
- Vue原始碼: 建構函式入口Vue原始碼函式
- C++ 建構函式實戰指南:預設構造、帶引數構造、複製構造與移動構造C++函式
- 【C++】初始化列表建構函式VS普通建構函式C++函式
- 11-建構函式函式
- 初識建構函式函式
- JavaScript Date()建構函式JavaScript函式
- 建構函式建立物件函式物件
- 建構函式詳解函式
- C++入門記-建構函式和解構函式C++函式
- 嬰兒的出生為你解惑建構函式和構造程式碼塊函式
- 【譯】JavaScript 工廠函式 vs 建構函式JavaScript函式
- vue原始碼解讀-建構函式Vue原始碼函式
- 建構函式定義的隱式型別轉換函式型別
- C++型別轉換建構函式C++型別函式
- 關於scala中的主建構函式函式
- Java中靜態程式碼塊、構造程式碼塊、建構函式、普通程式碼塊Java函式
- 建構函式之間的呼叫函式
- swoole 服務的建構函式函式
- js建構函式的繼承JS函式繼承