2015-01-19 14 views
22

मैं सी ++ कोड है जो निम्न की तरह कुछ करने पर निर्भर करता है:प्रारंभ स्थिरांक सदस्य चर

class Foo{ 
    bool bar; 
    bool baz; 
    Foo(const void*); 
}; 
Foo::Foo(const void* ptr){ 
    const struct my_struct* s = complex_method(ptr); 
    bar = calculate_bar(s); 
    baz = calculate_baz(s); 
} 

शब्दार्थ, बार और baz सदस्य चर, स्थिरांक होना चाहिए, क्योंकि वे प्रारंभ के बाद परिवर्तन नहीं होना चाहिए। हालांकि, ऐसा लगता है कि उन्हें ऐसा करने के लिए, उन्हें उन्हें असाइन करने की बजाय प्रारंभिक सूची में प्रारंभ करना होगा। स्पष्ट होने के लिए, मैं क्यों समझता हूं मुझे ऐसा करने की आवश्यकता है। समस्या यह है, मैं किसी भी तरह निम्नलिखित अवांछनीय चीजों में से एक कर के बिना एक प्रारंभ सूची में कोड परिवर्तित करने के लिए खोजने के लिए प्रतीत नहीं कर सकते हैं: दो बार

  • कॉल complex_method
  • जोड़ें (प्रदर्शन के लिए बुरा होगा) फू क्लास के सूचक (वर्ग आकार को अनावश्यक रूप से बड़ा कर देगा)

क्या इन अवांछनीय स्थितियों से बचते समय चर को बनाने का कोई तरीका है?

+0

एक तरफ के रूप में, क्या आप निश्चित हैं कि 'complex_method' सूचक द्वारा वापस आना चाहिए? और यदि ऐसा होता है, तो आपको इसे साफ़ करने की आवश्यकता नहीं है, जो इसे बचाने के लिए 'std :: unique_ptr' का उपयोग करने का सुझाव देता है? – Deduplicator

+0

ठीक है, मैंने ब्रेवटी के लिए उपरोक्त स्निपेट के लिए वास्तविक कोड को सरल बना दिया है। – dooglius

+2

सदस्यों को बनाने से बचें। यदि फू ऑब्जेक्ट नहीं बदला जाना चाहिए, तो इसके बजाय वास्तविक ऑब्जेक्ट कॉन्स बनाएं। –

उत्तर

25

, delegating constructors पर विचार करें:

class Foo 
{ 
    // ... 
    bool const bar; 
    bool const baz; 
    Foo(void const*); 
    // ... 
    Foo(my_struct const* s); // Possibly private 
}; 

Foo::Foo(void const* ptr) 
    : Foo{complex_method(ptr)} 
{ 
} 

// ... 

Foo::Foo(my_struct const* s) 
    : bar{calculate_bar(s)} 
    , baz{calculate_baz(s)} 
{ 
} 

एक सामान्य सलाह के रूप में, सावधान रहना अपने डेटा सदस्यों को const के रूप में घोषित करना, क्योंकि इससे आपकी कक्षा को कॉपी-असाइन करना और स्थानांतरित करना असंभव हो जाता है। यदि आपकी कक्षा को मूल्य अर्थशास्त्र के साथ उपयोग किया जाना चाहिए, तो वे ऑपरेशन वांछनीय हो जाते हैं। यदि ऐसा नहीं है, तो आप इस नोट को नजरअंदाज कर सकते हैं।

+2

यूवी, खासकर अंत में नोट के लिए। – Angew

8

आप सी ++ 11 में प्रतिनिधि निर्माता का उपयोग हो सकता है: आप एक सी ++ 11 संकलक खर्च कर सकते हैं, तो

class Foo{ 
public: 
    Foo(const void* ptr) : Foo(complex_method(ptr)) {} 

private: 
    Foo(const my_struct* s) : bar(calculate_bar(s)), baz(calculate_baz(s)) {} 

private: 
    const bool bar; 
    const bool baz; 
}; 
11

एक विकल्प एक सी ++ 11 प्रतिनिधि कन्स्ट्रक्टर है, जैसा कि अन्य उत्तरों में चर्चा की गई है।

class Foo{ 
    struct subobject { 
     const bool bar; 
     const bool baz; 
     subobject(const struct my_struct* s) 
      : bar(calculate_bar(s)) 
      , baz(calculate_baz(s)) 
     {} 
    } subobject; 
    Foo(const void*); 
}; 
Foo::Foo(const void* ptr) 
    : subobject(complex_method(ptr)) 
{} 

आप bar और baz स्थिरांक कर सकते हैं, या subobject स्थिरांक, या दोनों हो जाता है: सी ++ 03-संगत विधि एक subobject उपयोग करने के लिए है।

आप केवल subobject स्थिरांक बनाना है, तो आप complex_method की गणना और subobject के निर्माता के भीतर bar और baz को असाइन कर सकते हैं:

class Foo{ 
    const struct subobject { 
     bool bar; 
     bool baz; 
     subobject(const void*); 
    } subobject; 
    Foo(const void*); 
}; 
Foo::Foo(const void* ptr) 
    : subobject(ptr) 
{} 
Foo::subobject::subobject(const void* ptr){ 
    const struct my_struct* s = complex_method(ptr); 
    bar = calculate_bar(s); 
    baz = calculate_baz(s); 
} 

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

2

यदि आप नए फ़ंक्शंस प्रतिनिधि रचनाकारों का उपयोग नहीं करना चाहते हैं (मुझे अभी भी कंपाइलर संस्करणों से निपटना है जो उनके बारे में नहीं जानते हैं), और आप अपनी कक्षा के लेआउट को बदलना नहीं चाहते हैं, तो आप कर सकते हैं एक समाधान के लिए चयन करें जो के साथ तर्क के साथ पर लौटने वाले एक स्थिर कन्स्ट्रक्टर द्वारा तर्क को प्रतिस्थापित करता है, जबकि complex_method से आउटपुट को तर्क के रूप में आउटपुट लेता है (जो बाद में प्रतिनिधि कन्स्ट्रक्टर उदाहरणों की तरह होता है)।स्थिर सदस्य फ़ंक्शन complex_method से आवश्यक प्रारंभिक प्रारंभिक गणना करता है, और return Foo(s); के साथ समाप्त होता है। इसकी आवश्यकता होती है कि कक्षा में एक सुलभ प्रतिलिपि बनाने वाला हो, भले ही उसकी कॉल (return कथन में) शायद अधिकतर elided हो सकता है।

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