क्या उपयोगिता वर्ग कुछ भी नहीं है, लेकिन स्थिर सदस्य C ++ में एक विरोधी पैटर्न हैं?


39

प्रश्न मुझे ऐसे कार्यों को कहां से लाना चाहिए जो किसी वर्ग से संबंधित नहीं हैं, इस पर कुछ बहस छिड़ गई है कि क्या यह सी ++ में एक कक्षा में उपयोगिता कार्यों को संयोजित करने के लिए समझ में आता है या सिर्फ एक नामस्थान में मुफ्त कार्यों के रूप में मौजूद है।

मैं एक C # बैकग्राउंड से आता हूं, जहां बाद वाला विकल्प मौजूद नहीं है और इस तरह स्वाभाविक रूप से मेरे द्वारा लिखे गए C C ++ कोड में स्टैटिक क्लास का उपयोग करने की ओर रुझान है। उस सवाल पर सबसे ज्यादा वोट किए गए जवाब के साथ-साथ कई टिप्पणियों का कहना है कि मुक्त कार्यों को प्राथमिकता दी जानी है, यहां तक ​​कि स्थिर कक्षाओं का सुझाव भी एक विरोधी पैटर्न था। C ++ में ऐसा क्यों है? कम से कम सतह पर, एक वर्ग पर स्थिर तरीके एक नाम स्थान में मुक्त कार्यों से अप्रभेद्य लगते हैं। इस प्रकार बाद के लिए वरीयता क्यों?

क्या चीजें अलग होंगी, अगर उपयोगिता कार्यों के संग्रह के लिए कुछ साझा डेटा की आवश्यकता होती है, जैसे कि एक कैश एक निजी स्थिर क्षेत्र में स्टोर कर सकता है?


"कार्यात्मक अपघटन" एंटीपैटर्न की तरह थोड़ा सा लगता है।
user281377

7
संक्षिप्त उत्तर: इन कार्यों को पूरा करने के लिए आपको बस एक वर्ग की आवश्यकता नहीं है। फ्री फ़ंक्शंस आपके काम के लिए एक बहुत साफ-सुथरी फिट हैं जो उन्हें कुछ छद्म-ऊ निर्माण में क्रंच करने की तुलना में है, जो आपको केवल "विशुद्ध रूप से-ऊ" भाषाओं में चाहिए।
क्रिस का कहना है

जवाबों:


39

मैं उत्तर देने के लिए अनुमान लगाता हूं कि हमें दोनों वर्गों और नामस्थानों के इरादों की तुलना करनी चाहिए। विकिपीडिया के अनुसार:

कक्षा

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

नाम स्थान

सामान्य तौर पर, एक नेमस्पेस एक कंटेनर होता है जो इसे पहचानने वाले (नाम, या तकनीकी शब्द, या शब्द) के लिए संदर्भ प्रदान करता है और विभिन्न नामस्थानों में निवास करने वाले पहचानकर्ताओं के असंतोष की अनुमति देता है।

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

संभवतः तकनीकी कारण भी हैं, लेकिन जावा से आने वाले और बहु-प्रतिमान भाषा के आसपास मेरे सिर को पाने की कोशिश कर रहा है जो कि C ++ है, मेरे लिए सबसे स्पष्ट उत्तर है: क्योंकि हमें इसे प्राप्त करने के लिए OO की आवश्यकता नहीं है।


1
+1 के लिए "हमें इसे प्राप्त करने के लिए OO की आवश्यकता नहीं है"
Ixrec

मैं OO के नो-फैन के रूप में इससे सहमत हूं, लेकिन मुझे लगता है कि कुछ ऐसी परिस्थितियां हैं जहां ऑल-स्टैटिक क्लास का उपयोग करना एकमात्र समाधान है, उदाहरण के लिए, एक नाम स्थान की जगह, क्योंकि आप एक नेस्टेड नेमस्पेस घोषित नहीं कर सकते हैं। एक कक्षा।
वाल्ट बुग्लैग

26

मुझे लगता है कि एक विरोधी पैटर्न को कॉल करने में बहुत सावधानी होगी। नाम स्थान आमतौर पर पसंद किए जाते हैं, लेकिन जैसा कि कोई नामस्थान टेम्पलेट नहीं है और नामस्थान को टेम्पलेट पैरामीटर के रूप में पारित नहीं किया जा सकता है, कुछ भी नहीं के साथ कक्षाओं का उपयोग करते हुए, लेकिन स्थिर सदस्य काफी आम हैं।


3
अन्य उत्तर ओपी की अंतिम पंक्ति पर चमक गए हैं। नाम स्थान बहुत अधिक स्कोप नाम हैं, इसलिए यदि आपको अभिगम नियंत्रण की आवश्यकता है, तो कक्षाएं एकमात्र उपकरण उपलब्ध हैं।
cmannett85

2
@ cbamber85 निष्पक्ष होने के लिए, मैंने पहले दो उत्तरों को पढ़ने के बाद ही उस पंक्ति को रखा था ।
PersonalNexus

@PersonalNexus आह निष्पक्ष पर्याप्त, मुझे एहसास नहीं था!
cmannett85

10
@ cbamber85: यह पूरी तरह सच नहीं है। कार्यान्वयन फ़ाइल में "निजी" फ़ंक्शंस डालकर आप और भी बेहतर एनकैप्सुलेशन प्राप्त करेंगे, ताकि उपयोगकर्ताओं को निजी घोषणा भी देखने को न मिले।
अंकल बीन्स

2
+1 टेम्प्लेट वास्तव में एक ऐसा बिंदु है जहां नामस्थान में अभी भी सुविधाओं का अभाव है।
क्रिस ने

13

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

इसी तरह का मुद्दा यहाँ खेलने में है: C ++ में उपयोगिता कार्यों की मेजबानी के लिए स्थिर कक्षाओं का उपयोग करना C ++ के लिए एक विदेशी मुहावरा है।

जैसा कि आपने अपने प्रश्न में उल्लेख किया है, C # में यूटिलिटी फ़ंक्शंस के लिए स्टैटिक क्लासेस का उपयोग करना एक आवश्यकता की बात है: फ्री-स्टैंडिंग फ़ंक्शंस बस C # में एक विकल्प नहीं हैं। प्रोग्रामर को अनुमति देने के लिए एक पैटर्न विकसित करने के लिए आवश्यक भाषा किसी अन्य तरीके से मुक्त स्थैतिक कार्यों को परिभाषित करती है - अर्थात्, स्थिर उपयोगिता वर्गों के भीतर। यह एक जावा ट्रिक लिया गया शब्द-दर-शब्द है: उदाहरण के लिए, java.lang.Math और System.Math । NET के लगभग आइसोमॉर्फिक हैं।

C ++, हालांकि, नामस्थान प्रदान करता है, एक ही लक्ष्य को प्राप्त करने के लिए एक अलग सुविधा, और यह सक्रिय रूप से अपने मानक पुस्तकालय के कार्यान्वयन में इसका उपयोग करता है। स्टैटिक क्लासेस की एक अतिरिक्त लेयर जोड़ना न केवल अनावश्यक है, बल्कि C # या Java बैकग्राउंड के बिना भी कुछ हद तक पाठकों के लिए अनुकूल है। एक मायने में, आप किसी भाषा के लिए "ऋण अनुवाद" शुरू कर रहे हैं, जिसे मूल रूप से व्यक्त किया जा सकता है।

जब आपके कार्यों को डेटा साझा करने की आवश्यकता होती है, तो स्थिति अलग होती है। क्योंकि आपके कार्य अब असंबंधित नहीं हैं , इसलिए सिंगलटन पैटर्न इस आवश्यकता को संबोधित करने का पसंदीदा तरीका बन गया है।


6
+1, सिंगलेट्स की सिफारिश करने के अलावा। वे C ++ में पसंद नहीं किए जाते हैं ! यदि वे राज्य साझा करना चाहते हैं, तो कार्य एक वर्ग में हो सकते हैं, लेकिन कक्षाओं को तब तक एकल नहीं होना चाहिए जब तक कि वे वास्तव में होने की आवश्यकता न हो। और वे आमतौर पर नहीं है।
मैक्सएम

@Maxpm मुझे गलत मत समझो, सिंगलटन केवल वैश्विक स्थिर चर के लिए पसंद किया जाता है। इसके अलावा, उस बारे में "पसंदीदा" कुछ भी नहीं है।
dasblinkenlight

2
यह अच्छा लेख है, सिंगलनेट्स: सॉल्विंग प्रॉब्लम्स यू डोंट नॉट यू यू नेड हैड हैव 1995 से । संक्षेप में यह कहा गया है कि अच्छी तरह से ज्ञात उदाहरण को वर्ग में खुद को अनावश्यक रूप से जोड़ना आपके लचीलेपन को सीमित करता है और आपको कुछ भी नहीं देता है। अधिकांश समय बस एक वर्ग होता है और कहीं न कहीं एक साझा उदाहरण होता है, लेकिन इसे एकल नहीं बनाते हैं।
Jan Hudec

मुझे यकीन नहीं है कि "विदेशी मुहावरा" सही शब्द है। यह बहुत ही सामान्य मुहावरा है। मुझे लगता है कि काफी कुछ प्रोग्रामिंग टीमें स्ट्रॉस्ट्रुप के ई 2 का उपयोग कर रही हैं ...
निक कीघली

10

शायद आपको यह पूछने की ज़रूरत है कि आप एक ऑल-स्टैटिक क्लास क्यों चाहते हैं?

एकमात्र कारण जो मैं सोच सकता हूं, वह यह है कि अन्य भाषाएँ (जावा और C #) जो बहुत अधिक हैं 'सब कुछ एक वर्ग है' उनके लिए आवश्यक है। ये भाषाएं शीर्ष-स्तरीय फ़ंक्शन नहीं बना सकती हैं, इसलिए उन्होंने इन्हें रखने के लिए एक ट्रिक का आविष्कार किया, और वह था स्टैटिक मेंबर फंक्शन। वे थोड़े से वर्कअराउंड हैं, लेकिन C ++ को ऐसी किसी चीज़ की ज़रूरत नहीं है, आप सीधे नए टॉप-लेवल, स्वतंत्र फ़ंक्शंस बना सकते हैं।

यदि आपको ऐसे फ़ंक्शन की आवश्यकता होती है जो किसी विशिष्ट डेटा आइटम पर काम करते हैं, तो यह उन्हें डेटा को रखने वाले वर्ग में बंडल करने के लिए समझ में आता है, लेकिन फिर, ये कार्य बंद हो जाते हैं और उस वर्ग के सदस्य होने लगते हैं जो 'डेटा पर काम करते हैं।

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


10
वास्तव में - मैं कहूंगा कि जावा में "सभी स्थिर सदस्यों के साथ वर्ग" वास्तव में जावा की एक सीमा के आसपास प्राप्त करने के लिए एक हैक है।
चार्ल्स साल्विया

@CharlesSalvia: मैं विनम्र हो रहा था :) मुझे मुख्य () एक जावा वर्ग का हिस्सा होने के बारे में भी उतना ही बुरा लग रहा है, हालांकि मैं समझता हूं कि उन्होंने ऐसा क्यों किया।
gbjbaanb

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

5

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

दूसरे शब्दों में एक नाम स्थान के बजाय एक वर्ग होने का कोई लाभ नहीं है।

इस प्रकार बाद के लिए वरीयता क्यों?

एक बात के लिए यह आपको staticहर समय टाइप करने से बचाता है , हालांकि यह यकीनन एक मामूली लाभ है।

मुख्य लाभ यह है कि यह नौकरी के लिए कम से कम शक्तिशाली उपकरण है। कक्षाओं का उपयोग वस्तुओं को बनाने के लिए किया जा सकता है, उनका उपयोग चर के प्रकार या टेम्पलेट तर्क के रूप में किया जा सकता है। उनमें से कोई भी ऐसी विशेषताएं नहीं हैं जिन्हें आप अपने कार्यों के संग्रह के लिए चाहते हैं। तो यह एक उपकरण का उपयोग करना बेहतर होता है, जिसमें वे विशेषताएं नहीं होती हैं, ताकि कक्षा का गलती से दुरुपयोग न हो सके।

इसके बाद से एक नेमस्पेस का उपयोग करने से आपके कोड के किसी भी उपयोगकर्ता को तुरंत यह स्पष्ट हो जाता है कि यह फ़ंक्शन का संग्रह है, न कि ऑब्जेक्ट बनाने का ब्लूप्रिंट।


5

... हालांकि कई टिप्पणियों का कहना है कि मुक्त कार्यों को प्राथमिकता दी जानी है, यहां तक ​​कि स्थिर कक्षाओं का सुझाव भी एक विरोधी पैटर्न था। C ++ में ऐसा क्यों है? कम से कम सतह पर, एक वर्ग पर स्थिर तरीके एक नाम स्थान में मुक्त कार्यों से अप्रभेद्य लगते हैं। इस प्रकार बाद के लिए वरीयता क्यों?

ऑल-स्टैटिक क्लास को काम मिल जाएगा, लेकिन यह चिप्स और सालसा के लिए किराने की दुकान में 53 फुट का सेमी ट्रक चलाने जैसा है जब चार दरवाजों वाली सेडान (यानी, यह ओवरकिल होगी)। कक्षाएं अतिरिक्त ओवरहेड की एक छोटी मात्रा के साथ आती हैं और उनका अस्तित्व किसी को यह आभास दे सकता है कि किसी व्यक्ति को तत्काल विचार करना एक अच्छा विचार हो सकता है। C ++ (और C, जहां सभी कार्य मुफ्त हैं) द्वारा दिए गए नि: शुल्क फ़ंक्शन ऐसा नहीं करते हैं; वे सिर्फ कार्य कर रहे हैं और कुछ नहीं।

क्या चीजें अलग होंगी, अगर उपयोगिता कार्यों के संग्रह के लिए कुछ साझा डेटा की आवश्यकता होती है, जैसे कि एक कैश एक निजी स्थिर क्षेत्र में स्टोर कर सकता है?

ज़रुरी नहीं। staticC (और बाद में C ++) का मूल उद्देश्य लगातार भंडारण की पेशकश करना था जो किसी भी स्तर पर उपयोग करने योग्य है:

int counter() {
    static int value = 0;
    value++;
}

आप स्कोप को किसी फ़ाइल के स्तर तक ले जा सकते हैं, जो इसे सभी संकरे स्कोपों ​​के लिए दृश्यमान बनाता है, लेकिन फ़ाइल के बाहर नहीं:

static int value = 0;

int up() { value++; }
int down() { value--; }

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


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

यदि वे डेटा साझा करते हैं तो क्या वे स्थिर तरीकों के बिना एक वर्ग के रूप में बेहतर हो सकते हैं?
निक किली

@NickKeighley जो इस बात पर निर्भर करता है कि कौन इस बात पर बहस जीतता है कि क्या यह एक उदाहरण बनाने के लिए बेहतर है और इसे हर उस चीज़ के लिए पास करना चाहिए जो इसे ज़रूरत है या बस इसे स्थिर-इन-क्लास बनाएं।
ब्लरफ्ल

1

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


1

विषय पर प्रवचन की ज्यादातर यहाँ, समझ में आता है, हालांकि सी ++ के बारे में कि बनाता है बहुत ही मौलिक कुछ है namespacesऔर classes / structबहुत अलग है।

स्टैटिक क्लासेस (वे वर्ग जहाँ सभी सदस्य स्थिर होते हैं, और क्लास को कभी भी तत्काल नहीं बनाया जाएगा) स्वयं ऑब्जेक्ट हैं। वे केवल namespaceकार्य शामिल करने के लिए नहीं हैं।

टेम्प्लेट मेटा-प्रोग्रामिंग हमें एक स्थिर कक्षा को संकलन-समय ऑब्जेक्ट के रूप में उपयोग करने की अनुमति देता है।

इस पर विचार करो:

template<typename allocator_type> class allocator
{
public:
    inline static void* allocate(size_t size)
    {
        return allocator_type::template allocate(size);
    }
    inline static void release(void* p)
    {
        allocator_type::template release(p);
    }
};

इसका उपयोग करने के लिए हमें एक वर्ग के अंदर निहित कार्यों की आवश्यकता होती है। एक नाम स्थान यहां काम नहीं करेगा। विचार करें:

class mallocator
{
    inline static void* allocate(size_t size)
    {
        return std::malloc(size);
    }
    inline static void release(void* p)
    {
        return std::free(p);
    }
};

अब इसका उपयोग करने के लिए:

using my_allocator = allocator<mallocator>;

void* p = my_allocator::allocate(1024);
...
my_allocator::release(p);

इसलिए जब तक एक नया एलोकेटर एक allocateऔर releaseफ़ंक्शन को उजागर करता है, जो संगत है, एक नए आवंटनकर्ता के लिए स्विच करना आसान है।

यह नाम स्थान के साथ प्राप्त नहीं किया जा सकता है।

क्या आपको हमेशा कक्षा का हिस्सा होने के लिए कार्यों की आवश्यकता होती है? नहीं।

क्या स्थैतिक वर्ग का उपयोग प्रतिमान है? ये संदर्भ पर निर्भर करता है।

क्या चीजें अलग होंगी, अगर उपयोगिता कार्यों के संग्रह के लिए कुछ साझा डेटा की आवश्यकता होती है, जैसे कि एक कैश एक निजी स्थिर क्षेत्र में स्टोर कर सकता है?

उस स्थिति में, जो आप प्राप्त करने की कोशिश कर रहे हैं, वह ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग के माध्यम से सबसे अच्छा काम करने की संभावना है।


इनलाइन कीवर्ड का उपयोग यहाँ बेमानी है क्योंकि एक वर्ग परिभाषा में परिभाषित तरीके निहित रूप से इनलाइन हैं। En.cppreference.com/w/cpp/language/inline देखें ।
ट्रेवर

1

जॉन कार्मैक के रूप में प्रसिद्ध ने कहा:

"कभी-कभी, सुरुचिपूर्ण कार्यान्वयन केवल एक फ़ंक्शन है। कोई विधि नहीं। एक वर्ग नहीं। एक ढांचा नहीं। बस एक फ़ंक्शन।"

मुझे लगता है कि बहुत ज्यादा यह रकम है। यदि आप स्पष्ट रूप से एक वर्ग नहीं हैं तो आप इसे जबरदस्ती एक वर्ग क्यों बनायेंगे? सी ++ में लक्जरी है जिसे आप वास्तव में फ़ंक्शन का उपयोग कर सकते हैं; जावा में, सब कुछ एक विधि है। फिर आपको उपयोगिता वर्ग, और उनमें से बहुत सारे चाहिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.