2012-11-12 77 views
7

我有以下問題:我可以爲常量和非常量實例寫不同的copyCtor嗎?

我有一個類,它應該這樣做:

Obj o; 
Obj o1(o), o1=o; // deep-copies 
const Obj c(o), c=o; // deep-copies 
const Obj c1(c), c1=c; // shallow-copies 
Obj o2(c), o2=c; // deep-copies 

我怎樣才能做到這一點最好不繼承? (我的意思是我會做Const_objObj繼承除外。)

編輯:

直接使用o.clone()是不是一種選擇,因爲這樣我可以很容易地通過意外克隆引入錯誤。

編輯:

最後,有一個適當的,完全與惰性求使用想法從有效C++溶液通過斯科特邁爾斯。看看下面的答案。

+0

我想你可能需要添加一個clone()方法並且明確地做你想做的事情。 – Caribou

+0

這就是我想避免不寫幾乎不可追蹤的錯誤到我的代碼。這很容易。 –

+0

嗯,我認爲這樣做是非常危險的 - 特別是在你移動工作並且有新的進來之後...(我的2個penneth) – Caribou

回答

2

斯科特邁爾斯讀取有效C++後,以下是一種解決方案:

定義模板,其做了懶惰EVA luation(參考計數):

class Obj : private lazy<Obj_data>{}; 

和懶存儲Obj_data私下,已保護的存取器,一個用於修改,一個用於只讀訪問。
修改器訪問器首先根據需要深度複製Obj_data,然後將引用交給數據。只讀訪問器只是返回一個const引用。

這樣做的總體成本是存儲2個額外的指針(一個用於數據,一個用於計數器)和一個計數器。

實現是這樣的:

class lazy{ 
protected: 
    lazy(const lazy&obj){lazy_copy(obj);} 
    //(the required constructors, operator= ...) 

    // accessors: 
    const Obj_data& data() const {return *od;} 
    Obj_data& mod_data() {make_private(); return *od;} 
private: 
    void lazy_copy(const lazy& obj); 
    void make_private(); // this does the actual deep-copy, as late as possible. 
private: 
    counter*; 
    Obj_data* od; 
}; 

所以,在閱讀和修改的Obj屬性去

void Obj::method(){ 
    cout << data().some_attribute; // simple read 
    mod_data().i = 10;    // simple modify 
    const Obj_data& const_d = data(); // assignable for lots of read-outs 
    Obj_data& var_d = mod_data();  // assignable for lots of modifications. 
} 

請注意,您只能在const成員使用data()mod_data()是一個非-const函數,所以這個解決方案完全安全,開銷很小。

理論背景:問題中所需的行爲是實現細節,不涉及客戶端。因此我們通過私有繼承來解決它。

4

不,你不能。

  • 構造函數不能被cv限定,所以你不能強制它構造一個const對象。
  • 函數的返回類型(包括運算符)不是它的簽名的一部分,所以不能通過改變函數的返回類型來重載函數。

另外,如果有可能,我會發現它真的混淆。只要制定適合您需求的方法,並以明確的方式命名。

+0

這就是我的想法。 ( –

+0

)最後,找到了正確的實現方法,查看下面的答案 –

0

可以部分地與虛擬的說法:

class C { 
public: 
    struct NonStandardCopy { }; 

    C (const C &) { 
     // "ordinary" copy constructor with default behavior 
    } 

    C (const C &, NonStandardCopy) { 
     // "other" "copy" constructor 
    } 
}; 

C c = c1; // default 
C c (c1); // default 
C c (c1, C::NonStandardCopy()); // non-default 

編輯:只有A克隆的方法可能是你想要的(與移動語義一起對性能的影響可能不會太大)什麼:

class C { 
private: 
    struct DeepCopy { }; 
    struct ShallowCopy { }; 

    C (const C &) = delete; 

    C (const C &, DeepCopy) { 
     // deep copy 
    } 

    C (const C &, ShallowCopy) { 
     // shallow copy 
    } 
public: 
    // move constructor 
    C (C && other) = default; 

    const C clone() const { // 1 
     // shallow copy 
     return C (*this, ShallowCopy()); 
    } 

    C cloneToNonConst() const { // 2 
     // deep copy 
     return C (*this, DeepCopy()); 
    } 

    C clone() { // 3 
     return cloneToNonConst(); 
    } 
}; 

C o; 
C o1 = o.clone(); // call 3 
const C o2 = o1.clone(); // call 3 
const C o3 = o2.clone(); // call 1 
C c4 = o3.cloneToNonConst(); // call 2; o3.clone() will give error 
+0

+1,好想,我現在正在尋找使它自動化,我會回到這裏,寫一次我準備好使用'Const_obj/Obj'。 –

+0

很高興我的答案很有用,我只是明白你想區分構造一個const和構造一個非const。我認爲這在構造函數中是不可能的,然而,你可以使用public factory/clone函數(常量/非常量返回,常量與非常量成員函數)並聲明構造函數爲私有。 – JohnB

+0

對不起,但它還沒有爲我編譯時,我把測試到主函數,因爲copyCtor是私人。 –

相關問題