2010-06-01 17 views
6

मैं एक वर्ग में एक संरचना को परिवर्तित कर रहा था ताकि मैं अपने चर के लिए एक सेटर इंटरफेस को लागू कर सकूं।
मैं उन सभी उदाहरणों को बदलना नहीं चाहता था जहां चर पढ़ा गया था, हालांकि।इस सी ++ कॉन्स संदर्भ एक्सेसर इंटरफ़ेस idiom के साथ कोई समस्या है?

struct foo_t { 
    int x; 
    float y; 
}; 
इस के लिए

: तो मैं इस परिवर्तित

class foo_t { 
    int _x; 
    float _y; 
public: 
    foot_t() : x(_x), y(_y) { set(0, 0.0); } 

    const int &x; 
    const float &y; 

    set(int x, float y) { _x = x; _y = y; } 
}; 

मैं इस में दिलचस्पी रखता हूँ, क्योंकि यह सी # के सार्वजनिक केवल पढ़ने के लिए गुण के विचार मॉडल करने के लिए लगता है।
ठीक संकलित करता है, और मैंने अभी तक कोई समस्या नहीं देखी है।

कन्स्ट्रक्टर में कॉन्स्ट संदर्भों को जोड़ने के बॉयलरप्लेट के अलावा, इस विधि के डाउनसाइड्स क्या हैं?
कोई अजीब एलियासिंग मुद्दे?
मैंने इस मुहावरे को पहले क्यों नहीं देखा है?

+0

स्थिरांक पूर्णांक और एक्स क्यों है, कॉन्स फ्लोट और वाई; आवश्यक? – Arun

+0

@ अरुणशाहा वह बताते हैं कि उनके प्रश्न में। इसका उद्देश्य 'x' और' y' को "एक्सेसर" प्रदान करना है जो संरचना में चरों तक पहुंच के समान सिंटैक्स को बनाए रखता है। –

+1

सी # और सी ++ अपनी शैलियों और उपयोगों के साथ पूरी तरह से अलग भाषाएं हैं। दूसरी भाषा में एक भाषा की शैली की प्रतिलिपि बनाना बहुत सारी परेशानी का कारण बन रहा है, नई भाषा के लिए सबसे अच्छी तकनीक सीखना बहुत आसान है, जो ऐसी शैलियों की प्रतिलिपि नहीं है जो संगत नहीं हो सकते हैं (जैसे कि गेटर/सेटर की भयानक अवधारणा) –

उत्तर

5

इसमें एक एलियासिंग समस्या है क्योंकि आप foo_t के आंतरिक डेटा के संदर्भ का पर्दाफाश करते हैं, तो foo_t ऑब्जेक्ट के बाहर कोड के लिए ऑब्जेक्ट के जीवनकाल से परे अपने डेटा में संदर्भों को संदर्भित करना संभव है। पर विचार करें:

foo_t* f = new foo_t(); 
const int& x2 = f->x; 
delete f; 
std::cout << x2; // Undefined behavior; x2 refers into a foo_t object that was deleted 

या, और भी आसान:

const int& x2 = foo_t().x; 
std::cout << x2; // Undefined behvior; x2 refers into a foo_t object that no longer exists 

ये विशेष रूप से यथार्थवादी उदाहरण नहीं हैं, लेकिन जब भी एक वस्तु को उजागर करता है या (अपने डेटा के लिए एक संदर्भ सार्वजनिक या निजी रिटर्न इस में कोई समस्या है)। बेशक, foo_t के संदर्भ में अपने जीवनकाल से परे ऑब्जेक्ट को पकड़ना संभव है, लेकिन दुर्घटना से चूकना या करना मुश्किल हो सकता है।

यह नहीं कि आप जो कर रहे हैं उसके खिलाफ यह एक तर्क है। असल में मैंने इस पैटर्न का इस्तेमाल पहले (एक अलग कारण से) किया है और मुझे नहीं लगता कि इसमें कुछ भी गलत है, इसके अलावा encapsulation की कमी से, जिसे आप पहचानते हैं। उपर्युक्त मुद्दा केवल कुछ पता होना चाहिए।

+0

द्वारा उत्तर देखें मुझे इस तरह कुछ संदेह था - धन्यवाद। – mskfisher

0

आपका दृष्टिकोण लचीला नहीं है। जब आपके पास प्रत्येक चर के लिए getter/setter है तो इसका मतलब है कि यदि आप अपनी कक्षा में कुछ जोड़ते हैं तो आपको अपने set विधि को फिर से लिखना नहीं है।

यह अच्छा नहीं है क्योंकि आपके पास const और non-const गेटर्स (जो शायद ही कभी उपयोग किए जाते हैं, लेकिन कभी-कभी उपयोगी हो सकते हैं)।

आप संदर्भों की प्रतिलिपि नहीं बना सकते हैं, इसलिए, आपकी कक्षा गैर-प्रतिलिपि बन जाती है।

इसके अलावा, अपने वर्ग में प्रारंभ संदर्भित अतिरिक्त स्मृति का मतलब है और हम, के बारे में बात कर रहे हैं होने उदाहरण के लिए, शीर्ष वर्ग (हालांकि मुझे लगता है कि एक वर्ग वास्तव में नहीं होना चाहिए), यह एक आपदा बन सकता है।


[सब कुछ है कि इस प्रकार पूरी तरह से व्यक्तिपरक है]

getters और setters का उद्देश्य है, मेरे मन को, के बारे में साधारण संशोधन नहीं है, बल्कि गतिविधियों का क्रम है कि मूल्य संशोधन में परिणाम encapsulating के बारे में या मान देता है (जिसे हम दृश्यमान परिणाम के रूप में देखते हैं)।

आपके उदाहरण के मामले में व्यक्तिगत रूप से संरचना अधिक प्रभावी होगी, क्योंकि यह पीओडी डेटा को लपेटती है और तर्कसंगत रूप से "संरचना" करती है।

11

एक समस्या यह है कि आपकी कक्षा अब कॉपी करने योग्य या असाइन करने योग्य नहीं है, और इसलिए वेक्टरों जैसे सी ++ कंटेनर में संग्रहीत नहीं किया जा सकता है। दूसरा यह है कि आपके कोड को बनाए रखने वाले अनुभवी सी ++ प्रोग्रामर इसे देखेंगे और "डब्ल्यूटीएफ !!" बहुत जोर से, जो कभी अच्छी बात नहीं है।

+1

टच। लेकिन मैं उन्हें परिभाषित करके ठीक कर सकता था (जिसे मैंने ब्रेवटी के लिए छोड़ा था)। – mskfisher

+0

(मुझे यह पसंद है कि आपके संपादन ने मेरी टिप्पणी को अस्पष्ट कैसे बनाया - अब मैं या तो "प्रतिलिपि बनाने वाले प्रतिद्वंद्वियों" या "अनुभवी सी ++ प्रोग्रामर परिभाषित करने" का जिक्र कर रहा हूं।) – mskfisher

+0

@mskfisher इस तरह का आश्चर्य है - तथ्य यह है कि आपने टिप्पणी की है जवाब में सुधार से मुझे रोको। कोई भी जो भ्रमित है, हमेशा संपादन इतिहास को देख सकता है। और मुझे कहना होगा कि मैंने आपकी टिप्पणी को शुरू करने के लिए संदिग्ध पाया - मेरे मूल उत्तर के संदर्भ में "उन्हें" क्या हैं? –

2

तुम भी कुछ इस तरह है, जिसके लिए काम करता है कर सकता है प्रकार में बनाया गया: (क्षमा करें यह कोड स्निपेट त्रुटियाँ हैं, लेकिन आप विचार प्राप्त करता है, तो)

template <typename T, typename F> 
class read_only{ 
    typedef read_only<T, F> my_type; 
    friend F; 

public: 
    operator T() const {return mVal;} 

private: 
    my_type operator=(const T& val) {mVal = val; return *this;} 
    T mVal; 
}; 


class MyClass { 
public: 
    read_only <int, MyClass> mInt; 
    void MyFunc() { 
     mInt = 7; //Works 
    } 
}; 

AnyFunction(){ 
    MyClass myClass; 
    int x = myClass.mVal; // Works (okay it hasnt been initalized yet so you might get a warning =) 
    myClass.mVal = 7; // Error 
} 
+0

यह बहुत चालाक है मुझे कहना है। –

+0

मुझे यह भी पसंद है कि आपने रिटर्न-बाय-वैल्यू के लिए कॉन्स्ट संदर्भ को छोड़ दिया है, जो मेरी विधि के बारे में टायलर की शिकायत को समाप्त करता है। – mskfisher

+1

AFAIR टेम्पलेट पैरामीटर मित्र नहीं हो सकता है, इसलिए यह काम नहीं करेगा और यहां तक ​​कि अगर यह काम करता है तो यह "मित्र वर्ग एफ" होना चाहिए। इसके आसपास काम करने के लिए चालें हैं क्योंकि वे गंदा हैं और हर जगह काम नहीं करते हैं। – Tomek