2012-11-12 11 views
7

मैं निम्नलिखित समस्या है:क्या मैं कॉन्स और गैर-कॉन्स उदाहरणों के लिए अलग-अलग प्रतिलिपि लिख सकता हूं?

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_obj अन्यथा Obj से इनहेरिट करना होगा।)

संपादित करें:

सीधे o.clone() का उपयोग करते हुए एक विकल्प नहीं है क्योंकि तब मैं आसानी से गलती से नहीं क्लोनिंग द्वारा बग प्रस्तुत कर सकता है।

संपादित करें:

अंत में, एक उचित, पूरा आलसी मूल्यांकन के साथ विचार का उपयोग कर प्रभावी सी से समाधान ++ स्कॉट Meyers कर रहा है। नीचे मेरा जवाब देखें।

+0

मुझे लगता है कि आपको क्लोन() विधि जोड़ने और स्पष्ट रूप से जो करना है उसे करने की आवश्यकता हो सकती है। – Caribou

+0

यही वह है जो मैं अपने कोड में शायद ही ट्रैक करने योग्य बग नहीं लिखना चाहता हूं। यह इस तरह से इतना आसान है। –

+0

ठीक है, मुझे लगता है कि चुपचाप यह करना अधिक खतरनाक है - खासकर जब आप नौकरियों को ले जाते हैं और कोई नया आता है ... (मेरा 2 पैसा) – Caribou

उत्तर

2

स्कॉट Meyers द्वारा पढ़ने प्रभावी सी ++ के बाद, निम्न एक समाधान है (संदर्भ गिनती के साथ) luation:

class Obj : private lazy<Obj_data>{}; 

और आलसी भंडार Obj_data निजी तौर पर, accessors, संशोधन के लिए एक, केवल पढ़ने के लिए पहुँच के लिए एक संरक्षित किया गया है।
संशोधक एक्सेसर पहले आवश्यक होने पर Obj_data की गहरी प्रतिलिपि बनाता है, फिर डेटा के संदर्भ में हाथ। केवल-पढ़ने वाला एक्सेसर केवल एक कॉन्स्ट संदर्भ देता है।

इसकी कुल लागत 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. 
} 

नोट है कि आप केवल mod_data() के रूप में एक const सदस्य में data() उपयोग कर सकते हैं एक गैर है:

कार्यान्वयन कुछ इस तरह है कक्षा में -कॉन्स्ट फ़ंक्शन, इसलिए यह समाधान थोड़ा ओवरहेड के साथ पूरी तरह से सुरक्षित है।

सिद्धांत पृष्ठभूमि: प्रश्न में वांछित व्यवहार एक कार्यान्वयन विस्तार है, ग्राहक से कोई चिंता नहीं करता है। इसलिए हम इसे निजी विरासत से हल करते हैं।

4

नहीं, आप नहीं कर सकते।

  • एक निर्माता सीवी-योग्य नहीं हो सकता है, इसलिए आप इसे कॉन्स्ट ऑब्जेक्ट बनाने के लिए मजबूर नहीं कर सकते हैं।
  • फ़ंक्शन का प्रकार (ऑपरेटर समेत) इसके हस्ताक्षर का हिस्सा नहीं है, इसलिए आप केवल इसके रिटर्न प्रकार को बदलने के साथ फ़ंक्शन को अधिभारित नहीं कर सकते हैं।

इसके अलावा, अगर यह संभव था, मैं इसे वास्तव में भ्रामक पाते हैं। बस अपनी जरूरतों के अनुसार विधियों को बनाएं, और उन्हें एक स्पष्ट तरीके से नाम दें।

+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 

संपादित करें: एक क्लोन-केवल दृष्टिकोण हो सकता है कि आप क्या चाहते (एक साथ कदम अर्थ विज्ञान के साथ प्रदर्शन हिट बहुत बड़ा नहीं हो सकता है):

जो एक आलसी ईवा करता है एक टेम्पलेट को परिभाषित:

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

खुशी है कि मेरा जवाब उपयोगी है। मुझे बस समझ में आया कि आप एक कॉन्स बनाने और गैर-कॉन्स बनाने के बीच अंतर करना चाहते हैं। मुझे लगता है कि एक निर्माता के भीतर यह संभव नहीं है। हालांकि, आप सार्वजनिक कारखाने/क्लोन का उपयोग कर सकते हैं फ़ंक्शंस (कॉन्स/गैर-कॉन्स रिटर्निंग, कॉन्स बनाम गैर-कॉन्स सदस्य फ़ंक्शन) और रचनाकारों को निजी के रूप में घोषित करें। – JohnB

+0

क्षमा करें, लेकिन जब तक मैं कॉपी मुख्य रूप से परीक्षण नहीं करता तब से यह मेरे लिए संकलित नहीं होता है क्योंकि copyCtor निजी है –

संबंधित मुद्दे

 संबंधित मुद्दे