आपका कोड एक बहुत अच्छा लगता है जैसे कि आप एक अलग भाषा के आदी हैं - सी ++ में 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क्स का उपयोग करना चाहते हैं, जो मूल्यों पर सीमाओं के सेट हो सकते हैं सौंपा।
जब आप कक्षा में इनमें से किसी एक को एम्बेड करते हैं, तो आप इसे एक सार्वजनिक चर बनाते हैं, और सीमा अभी भी लागू होती है। क्लाइंट कोड में, सिंटैक्स पर कोई वास्तविक तर्क नहीं है - आप केवल एक सार्वजनिक चर को असाइन कर रहे हैं, जैसे कि आप किसी अन्य के साथ - मामूली विस्तार के साथ जो सीमा से बाहर एक मान असाइन करने का प्रयास कर रहे हैं, अपवाद फेंक देगा। सिद्धांत रूप में, कक्षा को शायद उस मामले में क्या करना है, यह निर्दिष्ट करने के लिए नीति टेम्पलेट-पैरामीटर लेना चाहिए, लेकिन मेरे पास इसके साथ परेशान करने का वास्तविक कारण कभी नहीं था।
आप अपने संपादन प्रतिबिंबित करने के लिए अपने उदाहरण संपादित करना चाहते हो सकता है:
इसके बजाय, इस तरह से अपनी गेटर लिखें। अभी आप एक गैर-कॉन्स पॉइंटर लौट रहे हैं। –
लेकिन फिर मैं खुद को स्मृति को हटाने में सक्षम नहीं होगा? मुझे यह जानने की ज़रूरत है कि वेरिएबल्स का सही स्वामित्व कैसे लें और दूसरों को अंडरलिंग चर को संशोधित किए बिना गेटर्स को कॉल करने दें ... – Jonathan
गेटर्स और सेटर्स बहुत जावा/सी # शैली (सी ++ नहीं) हैं। वे ऑब्जेक्ट बनाने के लिए प्रतिबिंब और ढांचे पर इन भाषाओं के निर्भरता का परिणाम हैं। गेटर्स और सेटर एक भाषा की ओओ प्रकृति को नष्ट कर देते हैं और स्पष्ट रूप से आपको किसी ऑब्जेक्ट की आंतरिक संरचना में हस्तक्षेप करने की अनुमति देते हैं। सी ++ में यह डूब गया है कि कन्स्ट्रक्टर पूरा होने के बाद वस्तु पूरी तरह से बनाई गई है। –