2009-10-20 13 views
10

मैं सी ++ गेटर्स और सेटर्स के लिए एक अच्छा वाक्यविन्यास जानना चाहता हूं।सी ++ में उपयोग करने के लिए गेटर और सेटर, पॉइंटर्स या संदर्भ, और अच्छा वाक्यविन्यास?

void Member(YourClass *value){ 
    this->pMember = value; // forget about deleting etc 
} 

और गेटर:

private: 
YourClass *pMember; 

सेटर मुझे लगता है कि आसान है? क्या मुझे संदर्भ या कॉन्स्ट पॉइंटर्स का उपयोग करना चाहिए?

उदाहरण:

YourClass &Member(){ 
    return *this->pMember; 
} 

या

YourClass *Member() const{ 
    return this->member; 
} 

क्या उन दोनों के बीच क्या अंतर है?

धन्यवाद,

जो

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

माफ करना, मैं अपने प्रश्न संपादित करेंगे ... मैं संदर्भ और संकेत के बारे में पता है, मैं ही टिककर खेल के रूप में, संदर्भ और स्थिरांक संकेत के बारे में पूछ रहा था, क्या मेरी कोड में उन दोनों के बीच अंतर हो जाएगा, hte भविष्य में की तरह, मैं अगर मैं एक तरह से या किसी अन्य जाना कम करने के लिए क्या उम्मीद shoud ...

तो

मुझे लगता है मैं संदर्भ

बजाय स्थिरांक संकेत का उपयोग करेगा

कॉन्स्ट पॉइंटर्स को हटाया या सेट नहीं किया जा सकता है, है ना?

+0

आप अपने संपादन प्रतिबिंबित करने के लिए अपने उदाहरण संपादित करना चाहते हो सकता है:

इसके बजाय, इस तरह से अपनी गेटर लिखें। अभी आप एक गैर-कॉन्स पॉइंटर लौट रहे हैं। –

+0

लेकिन फिर मैं खुद को स्मृति को हटाने में सक्षम नहीं होगा? मुझे यह जानने की ज़रूरत है कि वेरिएबल्स का सही स्वामित्व कैसे लें और दूसरों को अंडरलिंग चर को संशोधित किए बिना गेटर्स को कॉल करने दें ... – Jonathan

+0

गेटर्स और सेटर्स बहुत जावा/सी # शैली (सी ++ नहीं) हैं। वे ऑब्जेक्ट बनाने के लिए प्रतिबिंब और ढांचे पर इन भाषाओं के निर्भरता का परिणाम हैं। गेटर्स और सेटर एक भाषा की ओओ प्रकृति को नष्ट कर देते हैं और स्पष्ट रूप से आपको किसी ऑब्जेक्ट की आंतरिक संरचना में हस्तक्षेप करने की अनुमति देते हैं। सी ++ में यह डूब गया है कि कन्स्ट्रक्टर पूरा होने के बाद वस्तु पूरी तरह से बनाई गई है। –

उत्तर

15

एक सामान्य कानून के रूप में:

  • अगर शून्य एक वैध पैरामीटर या वापसी मान, उपयोग संकेत दिए गए है।
  • यदि NULL मान्य पैरामीटर या वापसी मान नहीं है, तो संदर्भों का उपयोग करें।

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

यदि यह एक नल पॉइंटर वाले ऑब्जेक्ट के गेटर को कॉल करने के लिए मान्य है, तो उसे एक पॉइंटर वापस करना चाहिए। यदि ऐसा मामला एक अवैध आविष्कार है, तो वापसी मूल्य एक संदर्भ होना चाहिए। अगर सदस्य परिवर्तक नल है तो गेटटर को अपवाद फेंकना चाहिए।

+0

कैसे: अगर शून्य वैध पैरामीटर या वापसी मान नहीं है, तो मूल्य से वापसी का उपयोग करें? (कोई पॉइंटर्स नहीं, कोई रेफरी नहीं) – hasen

+0

यह सरल तरीका है। लेकिन फिर सवाल सही ढंग से जवाब देने के लिए सामान्यीकृत करने का तरीका है। –

+0

मैं केवल अंतर्निर्मित के लिए मूल्य द्वारा वापसी का उपयोग करता हूं, बाकी के लिए मैं कॉपी-निर्माण की लागत से बचाना चाहता हूं। // गेटर्स के लिए, निश्चित रूप से यदि आपको कुछ गणना करने की आवश्यकता है, तो यह अलग है –

2

उनके बीच क्या अंतर है?

संदर्भ बात का अन्य नाम है (यह बात है *)। एक सूचक बात का पता है। यदि कोई मौका है कि जो इंगित किया गया है वह वहां नहीं होगा, तो शायद आप संदर्भ वापस नहीं करना चाहते हैं। संदर्भ कॉलर को बताते हैं "मैं आपको एक उपनाम देने जा रहा हूं जो आपके पास वापस आने पर अस्तित्व में रहेगा"। असल में यह देखने के लिए वास्तव में कोई तरीका नहीं है कि क्या अंतर्निहित है वैध है या नहीं।

पॉइंटर के साथ, अर्थात्, आप यह कह रहे हैं कि कॉलर यह देखने के लिए जांच कर सकता है कि सदस्य इसका उपयोग करने से पहले मौजूद है या नहीं। आम तौर पर यह एक पूर्ण जांच के साथ किया जाता है।

आखिरकार कोई "सही" उत्तर नहीं है। यह कक्षा के अनुबंध पर निर्भर करता है और यदि कॉलर यह जांचना चाहता/चाहती है कि "सदस्य" अभी भी आसपास है या नहीं।

संक्षिप्त उत्तर उन चीज़ों के लिए पॉइंटर्स है जिन्हें कहीं और और "असीमित" उपनामों के संदर्भों के लिए संदर्भित किया जा सकता है।

+0

क्षमा करें, मैं अपना प्रश्न संपादित करूंगा ... मुझे संदर्भ और पॉइंटर्स के बारे में पता है, मैं संदर्भों और कॉन्स्ट पॉइंटर्स के बारे में पूछ रहा था, गेटर्स के रूप में, क्या होगा मेरे कोड में उनके बीच अंतर हो, जैसे कि एचटीई भविष्य में, अगर मैं किसी अन्य तरीके से जाता हूं तो मैं क्या खोने की उम्मीद करता हूं ... – Jonathan

7

सबसे अच्छी बात यह है कि क्लाइंट को वास्तविक ओओ इंटरफ़ेस प्रदान करना है जो कार्यान्वयन विवरण छुपाता है। गेटर्स और सेटर्स ओओ नहीं हैं।

+0

मैं हूं, लेकिन मुझे सार्वजनिक चर के बजाय गेटर्स और सेटर्स पसंद हैं। मैं केवल सार्वजनिक चर का उपयोग करता हूं, केवल तभी आवश्यक होता है, या कम से कम संरक्षित चर – Jonathan

+6

मुझे लगता है कि देवफ्रेड क्या सुझाव दे रहा है कि आप दोनों गेटर्स/सेटर्स और सार्वजनिक चर से बचें। इसके बजाय, सक्रिय विधियों को परिभाषित करने का प्रयास करें जो आपके लिए काम करते हैं। – Boojum

+0

क्या आप मुझे एक उदाहरण दे सकते हैं? मैं अमूर्त कक्षाएं बना रहा हूं और उनसे प्राप्त कर रहा हूं और मेरे अधिकांश गेटर्स, सेटर्स और फ़ंक्शंस वर्चुअल हैं ... मुझे लगता है कि मुझे वह नहीं मिला जो उसका मतलब था – Jonathan

1

+1 सेटर्स और गेटर्स के उपयोग पर सवाल पूछने पर +1। यदि आपको उनका उपयोग करना चाहिए और बूस्ट :: shared_ptr का उपयोग करने पर विचार करने की संभावना है। इस तरह स्वामित्व आपके लिए संभाला जाता है।

+0

मैं अभी तक बूस्ट का उपयोग नहीं करना चाहूंगा, जैसा कि मैं सीख रहा हूं, मैं इस परियोजना को कम बाहरी पुस्तकालयों के साथ बनाना चाहता हूं ... – Jonathan

+0

'boost :: shared_ptr' अब आधुनिक सी ++ में' std :: shared_ptr' है , इसलिए बाह्य निर्भरता अब स्मार्ट पॉइंटर्स का उपयोग न करने का बहाना नहीं है। – ulidtko

4

जैसा कि अन्य ने कहा है, अगर नल संभावना है तो पॉइंटर्स का उपयोग करें।

ज्यादातर मामलों में, जब भी संभव हो, मैं संदर्भों का उपयोग करना पसंद करता हूं। निजी तौर पर, मेरे कोड में, मैं सिग्नल स्वामित्व के लिए पॉइंटर्स और संदर्भों के बीच भेद का उपयोग करना पसंद करता हूं। मैं किसी अन्य कार्य या कक्षा में ऑब्जेक्ट को "ऋण" के रूप में संदर्भों के साथ कॉल के बारे में सोचता हूं। संदर्भित या पारित मूल वर्ग अभी भी इसका मालिक है, और इसके निर्माण, रखरखाव और सफाई के लिए ज़िम्मेदार है। जब मेरा कोड एक गैर-कॉन्स्ट पॉइंटर पास करता है, दूसरी ओर, आमतौर पर इसका मतलब है कि किसी भी तरह का स्थानांतरण या स्वामित्व साझा करना है, जिसमें सभी जिम्मेदारियां हैं।

(और हाँ, मैं आमतौर पर स्मार्ट संकेत का उपयोग करें। उन मेरे मन में संदर्भ के लिए समान हैं। मैं यहाँ से कम स्तर कोड के बारे में बात कर रहा हूँ।)

0

जोनाथन, क्या संकलक आप उपयोग कर रहे हैं? एक शानदार मौका है कि shared_ptr संकलक के TR1 कार्यान्वयन के हिस्से के रूप में पहले ही इसके साथ भेज दिया जाता है।

6

आपका कोड एक बहुत अच्छा लगता है जैसे कि आप एक अलग भाषा के आदी हैं - सी ++ में this->x (एक उदाहरण के लिए) का उपयोग अपेक्षाकृत असामान्य है। जब कोड अच्छी तरह से लिखा जाता है, तो एक एक्सेसर या म्यूटेटर का उपयोग कर रहा है।

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

कब/यदि आपको नियंत्रित करने की आवश्यकता है कि कौन सा मान असाइन किया गया है, तो ऑपरेटर ओवरलोडिंग आपको क्लाइंट कोड पर बदसूरत/सेट सिंटैक्स को मजबूर किए बिना उस नियंत्रण को लेने देता है। विशेष रूप से, आप जो चाहते हैं वह प्रॉक्सी क्लास (या क्लास टेम्पलेट) है। सिर्फ एक उदाहरण के लिए, सबसे सामान्य परिस्थितियों में से एक जहां लोग प्राप्त/सेट फ़ंक्शंस चाहते हैं, वह ऐसी संख्या की तरह है जो किसी विशेष सीमा तक सीमित होना चाहिए। setXXX सीमा में होने के लिए नए मान की जांच करता है, और getXXX मान देता है।

आपको लगता है कि, एक (काफी) सरल टेम्पलेट काम और अधिक सफाई से कर सकते हैं चाहते हैं:

template <class T, class less=std::less<T> > 
class bounded { 
    const T lower_, upper_; 
    T val_; 

    bool check(T const &value) { 
     return less()(value, lower_) || less()(upper_, value); 
    } 

    void assign(T const &value) { 
     if (check(value)) 
      throw std::domain_error("Out of Range"); 
     val_ = value; 
    } 

public: 
    bounded(T const &lower, T const &upper) 
     : lower_(lower), upper_(upper) {} 

    bounded(bounded const &init) 
     : lower_(init.lower), upper_(init.upper) 
    { 
     assign(init); 
    } 

    bounded &operator=(T const &v) { assign(v); return *this; } 

    operator T() const { return val_; } 

    friend std::istream &operator>>(std::istream &is, bounded &b) { 
     T temp; 
     is >> temp; 

     if (b.check(temp)) 
      is.setstate(std::ios::failbit); 
     else 
      b.val_ = temp; 
     return is; 
    } 
}; 

यह भी कोड बहुत स्वयं कुछ दस्तावेज़ीकृत के करीब बना देता है - उदाहरण के लिए, जब आप एक वस्तु की घोषणा जैसे: bounded<int>(1, 1024);, यह तुरंत स्पष्ट है कि इरादा 1 से 1024 की सीमा में एक पूर्णांक है। केवल एक ही भाग प्रश्न के लिए खुलासा यह है कि श्रेणी में 1 और/या 1024 शामिल है या नहीं।कक्षा में एक इंटीरियर को परिभाषित करने से यह काफी अलग है, और उम्मीद है कि कक्षा में कभी भी यह देखने के लिए कि वे कुछ को (उस बिंदु पर अज्ञात) लागू करने के लिए सेटXXक्स का उपयोग करना चाहते हैं, जो मूल्यों पर सीमाओं के सेट हो सकते हैं सौंपा।

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

+2

क्षमा करें, लेकिन उस कोड को देखते हुए गेटटर या सेटर की तुलना में समझने के लिए बहुत कठिन (कम से कम मेरे लिए) बनाता है। मेरे लिए यह सोचना आसान नहीं है कि एक साधारण नियम के लिए एक टेम्पलेट श्रेणी या सिर्फ एक वर्ग बनाना एक साधारण सेट फ़ंक्शन से बेहतर है। एक बड़ी लाइब्रेरी के बारे में सोचें जो अन्य पुस्तकालयों या निष्पादन योग्यों द्वारा उपयोग की जा रही है, मुझे लगता है कि असाइनमेंट ऑपरेटर को अधिभारित करना सबसे अच्छा तरीका नहीं है, बेशक मैं सिर्फ एक नौसिखिया हूं, लेकिन जो मैंने पढ़ा है, उससे असाइनमेंट ऑपरेटर चाहिए जब आवश्यक रूप से आवश्यक पेड़ की तरह, मार्टिन ने मेरे – Jonathan

+2

के अन्य धागे में लिखा था कि पेड़ के नियम की तरह ही अधिभारित किया जाना चाहिए यदि आप जो भी लिखने जा रहे थे वह एक गेटर और एक सेटर था, तो आप सही होंगे - यह कोड अधिक जटिल होगा। जब आप एक टेम्पलेट के साथ दर्जनों (संभावित रूप से सैकड़ों) गेटर्स और सेटर्स को प्रतिस्थापित कर सकते हैं, हालांकि, यह कोड को काफी सरल बनाता है। इसके बावजूद, यह सभी जटिलताओं को केंद्रीकृत करता है। एक गेटर और सेटर को सभी * कोड * कार्यान्वयन के बारे में जागरूक होने और इसके साथ निपटने के लिए जटिलता जोड़ने की आवश्यकता होती है। यह सभी जटिलताओं को एक ही स्थान पर रखता है, और अन्य सभी कोड को सरल बनाता है। –

1

अन्य उत्तर के अलावा, यदि आप गेटर के लिए संदर्भ चुनें यह आपके उदाहरण की तरह कुछ भी न लिखें:

YourClass &Member(){ 
    return *this->pMember; 
} 

आपका गेटर वास्तव में, सेटिंग की अनुमति देता है में instance->Member() = YourClass(); और इस तरह अपने सेटर को दरकिनार के रूप में। यदि आपकी क्लास अपरिवर्तनीय है, तो इसकी अनुमति नहीं दी जा सकती है, लेकिन अभी भी एक और बात ध्यान में रखना है। एक और कमी यह है कि गेटर नहीं है।

const YourClass &Member() const { 
    return *this->pMember; 
} 
संबंधित मुद्दे