हम निजी सदस्य कार्यों को हेडर में क्यों रखते हैं?


16

हम C ++ हेडर में निजी सदस्य चर क्यों डालते हैं इसका उत्तर यह है कि वर्ग का आकार उन बिंदुओं पर जाना चाहिए जहां उदाहरण घोषित किए गए हैं ताकि कंपाइलर कोड उत्पन्न कर सके जो स्टैक के बारे में उचित रूप से चलता है।

हमें निजी सदस्यों को हेडर में रखने की आवश्यकता क्यों है?

लेकिन क्या कक्षा की परिभाषा में निजी कार्यों को घोषित करने का कोई कारण है?

विकल्प अनिवार्य रूप से दाना मुहावरा होगा लेकिन बिना अतिरेक के अप्रत्यक्ष।

क्या यह भाषा एक ऐतिहासिक त्रुटि से अधिक है?

जवाबों:


11

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

ऐसा लग सकता है कि यह "घोड़े के आगे गाड़ी लगाने" जैसा है, क्योंकि संकलक कार्यान्वयन विकल्पों को भाषा विनिर्देश को प्रभावित नहीं करना चाहिए। हालाँकि, वास्तव में C ++ भाषा का विकास उसी समय एक कार्यशील कार्यान्वयन ( Cfront ) के रूप में हुआ था, जिसमें vtables का उपयोग किया जाता था।


4
"कार्यान्वयन विकल्प भाषा को प्रभावित नहीं करना चाहिए" C ++ मंत्र के लगभग विपरीत है। विनिर्देश किसी विशेष कार्यान्वयन को अनिवार्य नहीं करता है, लेकिन विशेष रूप से कुशल कार्यान्वयन विकल्प की आवश्यकताओं को पूरा करने के लिए विशेष रूप से तैयार किए गए बहुत सारे नियम हैं।
बेन वोइगेट

यह बहुत प्रशंसनीय लगता है। क्या इस पर कोई स्रोत है?
प्रिक्सोलिटिक

@Praxeolitic: आप वर्चुअल मेथड टेबल के बारे में पढ़ सकते हैं ।
ग्रेग हेविल

1
@Praxeolitic - 'एनोटेटेड C ++ रेफरनस मैनुअल' ( stroustrup.com/arm.html ) की एक पुरानी प्रति - लेखक विभिन्न कार्यान्वयन विवरणों के बारे में बात करते हैं और यह कैसे भाषा को आकार देते हैं।
माइकल कोहेन

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

13

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

यह तुरंत निजी और संरक्षित डेटा सदस्यों के लिए सभी क्लाइंट कोड तुच्छ पहुंच प्रदान करेगा।

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


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

ये पहुँच विनिर्देशक इन हमलों को रोकने की कोशिश नहीं करते, क्योंकि यह संभव नहीं है। वे केवल यह इंगित करते हैं कि एक वर्ग का उपयोग कैसे किया जाना चाहिए।


1
वर्ग परिभाषा क्लाइंट कोड से छिपाए गए फ़ंक्शन कंटेनर इकाई को संदर्भित कर सकती है। वैकल्पिक रूप से, यह उलटा हो सकता है और क्लाइंट कोड से छिपी एक पूर्ण पारंपरिक वर्ग परिभाषा एक दृश्य इंटरफ़ेस को निर्दिष्ट कर सकती है जो केवल सार्वजनिक सदस्यों का वर्णन करती है और इसके आकार को प्रकट कर सकती है।
१४:१४ पर प्रेक्सालिटिक

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

यह एक अच्छी बात है, लेकिन क्या यह सभी सदस्य कार्यों की परिभाषाओं के लिए सही नहीं है, वैसे भी हेडर में नहीं?
प्रिक्सोलिटिक

1
सभी सदस्य कार्यों को कक्षा के अंदर घोषित किया जाता है। मुद्दा यह है कि आप नए सदस्य कार्य नहीं जोड़ सकते हैं जिन्हें कम से कम वर्ग परिभाषा में घोषित नहीं किया गया था (और एक परिभाषा नियम कई परिभाषाओं को रोकता है)।
बेकार

फिर निजी कार्यों के एक कंटेनर के बारे में क्या नियम है?
प्रैक्सियोलाइटिक

8

स्वीकृत उत्तर इसे आभासी निजी कार्यों के लिए समझाता है , लेकिन यह केवल प्रश्न के एक विशिष्ट पहलू का उत्तर देता है, जो कि ओपी द्वारा पूछे गए प्रश्नों की तुलना में काफी सीमित है। इसलिए, हमें पुन: प्रयास करने की आवश्यकता है: हमें हेडर में गैर-आभासी निजी कार्यों की घोषणा करने की आवश्यकता क्यों है ?

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

इसलिए, मैं एक उत्तर प्रदान करना चाहता था, जो कि डिफ़ॉल्ट रूप से निजी तरीकों को शामिल करने के बजाय, उपयोगकर्ताओं को दिखाई देने के पक्ष में विशिष्ट बिंदु प्रदान करता है। सार्वजनिक घोषणा की आवश्यकता वाले गैर-आभासी निजी कार्यों के लिए एक यंत्रवत कारण हर्ब सटर के गॉटडब्ल्यू # 100 में अपने तर्क के हिस्से के रूप में पिंपल मुहावरे के बारे में दिया गया है। मैं यहाँ पिम्पल के बारे में नहीं जाऊँगा, क्योंकि मुझे यकीन है कि हम सभी इसके बारे में जानते हैं। लेकिन यहाँ प्रासंगिक सा है:

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

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

बेशक, समिति के सदस्य के रूप में एक अत्यंत विश्वसनीय स्रोत है, इसलिए जब वह किसी को देखता है, तो वह "जानबूझकर डिजाइन निर्णय" जानता है। और बाद में बदले हुए शब्दार्थ या आकस्मिक रूप से टूटी पहुंच से बचने के लिए निजी तरीकों की सार्वजनिक घोषणा की आवश्यकता का विचार शायद सबसे ठोस तर्क है। शुक्र है, जैसा कि अब से पहले पूरी बात व्यर्थ लग रही थी!


" लेकिन फिर आप पूछते हैं कि क्यों, और यह उत्तर टॉटोलॉजिकल लगता है। फिर, क्लास के उपयोगकर्ताओं को उनके बारे में जानने की आवश्यकता क्यों है? " नहीं, यह टॉटोलॉजिकल नहीं है। उपयोगकर्ताओं को "उनके बारे में जानना आवश्यक नहीं है"। क्या होने की जरूरत है कि आपको लोगों को वर्ग लेखक की सहमति के बिना कक्षाओं को विस्तारित करने से रोकने में सक्षम होना चाहिए। तो ऐसे सभी सदस्यों को अप-फ्रंट घोषित किया जाना चाहिए। यह उपयोगकर्ताओं को निजी सदस्यों के बारे में जानने का कारण बनता है, यह केवल एक आवश्यक परिणाम है।
निकोल बोलस

1
@NicolBolas यकीन के लिए। वह शायद मेरी ओर से बहुत अच्छा शब्द नहीं था। मेरा मतलब था कि उत्तर केवल (बहुत ही मान्य) नियम के परिणामस्वरूप निजी तरीकों की दृश्यता को स्पष्ट करता है जो विशेष रूप से निजी तरीकों की दृश्यता के बारे में एक तर्क प्रदान करने के बजाय कई चीजों को शामिल करता है। बेशक, असली जवाब बेकार है, gnasher, और मेरा का एक संयोजन है। मैं सिर्फ एक और दृष्टिकोण प्रदान करना चाहता हूं जो अभी तक यहां नहीं था।
अंडरस्कोर_ड

4

ऐसा करने के दो कारण हैं।

सबसे पहले, महसूस करें कि एक्सेस स्पेसियर कंपाइलर के लिए है , और रनटाइम पर प्रासंगिक नहीं है। दायरे से बाहर एक निजी सदस्य तक पहुंचना एक संकलित त्रुटि है।

संक्षिप्ति

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

क्या आपके पास हेडर में एक त्वरित या दो लाइन होगी, या फ़ंक्शन प्रोटोटाइप है और साथ ही कहीं एक कार्यान्वयन? हेडर में खोजना आसान है, और छोटे कार्यों के लिए, एक अलग कार्यान्वयन के लिए कहीं अधिक क्रिया है।

एक और बड़ा फायदा है, जो ...

इनलाइन कार्य

एक निजी फ़ंक्शन इनबिल्ड हो सकता है, और इसके लिए हेडर में होना आवश्यक है। इस पर विचार करो:

class A {
  private:
    inline void myPrivateFunction() {
      ...
    }

  public:
    inline void somePublicFunction() {
      myPrivateFunction();
      ...
    }
};

निजी फ़ंक्शन सार्वजनिक फ़ंक्शन के साथ-साथ इनबिल्ट होने में सक्षम हो सकता है। यह कंपाइलर के विवेक पर किया जाता है, क्योंकि inlineकीवर्ड तकनीकी रूप से एक सुझाव है , आवश्यकता नहीं।


वर्ग निकाय के अंदर परिभाषित सभी फ़ंक्शन स्वचालित रूप से चिह्नित हैं inline, वहां कीवर्ड का उपयोग करने का कोई कारण नहीं है।
बेन वोयगेट

@BenVoigt तो यह है। मुझे यह एहसास नहीं था, और मैं काफी समय से C ++ पार्ट-टाइम का उपयोग कर रहा हूं। वह भाषा मुझे उस तरह के छोटे नगों के साथ आश्चर्यचकित करने के लिए कभी नहीं रोकता है।

मुझे नहीं लगता कि शीर्षासन करने के लिए किसी विधि की आवश्यकता है। इसे बस एक ही संकलन इकाई में होना चाहिए। क्या कोई ऐसा मामला है जहाँ एक वर्ग के लिए अलग संकलन इकाइयाँ होना मायने रखता है?
सैमुअल डेनियलसन

@SamuelDanielson सही है, लेकिन एक निजी फ़ंक्शन को कक्षा की परिभाषा में होना चाहिए। "निजी" की बहुत धारणा का अर्थ है कि यह कक्षा का हिस्सा है। यह संभव है .cppकि फ़ाइल में एक nonmember फ़ंक्शन हो जो सदस्य परिभाषा द्वारा इनबिल्ड हो जो कि क्लास डेफिनेशन के बाहर परिभाषित हो, लेकिन ऐसा फ़ंक्शन निजी नहीं होगा।

प्रश्न का मुख्य भाग "क्या वर्ग परिभाषा में निजी कार्यों को घोषित करने का कोई कारण है [sic, जिसके संदर्भ में ओपी वास्तव में वर्ग घोषणा का मतलब दर्शाता है]"। आप निजी कार्यों को परिभाषित करने के बारे में बात कर रहे हैं। इस सवाल का जवाब नहीं है। @SamuelDanielson आजकल LTO का मतलब है कि प्रोजेक्ट किसी भी जगह पर हो सकते हैं और इनबिल्ट होने के समान अवसर को बनाए रख सकते हैं। एक कक्षा को कई अनुवाद इकाइयों में विभाजित करने के लिए, सबसे सरल मामला यह है कि कक्षा सिर्फ बड़ी है और आप इसे कई स्रोत फ़ाइलों में विभाजित करना चाहते हैं। मैं वैसे भी यकीन है कि इतनी बड़ी कक्षाओं हतोत्साहित किया जाता है, लेकिन कर रहा हूँ
underscore_d

2

हेडर फ़ाइल में निजी तरीकों के होने का एक और कारण: ऐसे मामले हैं जहां एक सार्वजनिक इनलाइन विधि एक या कई निजी तरीकों को कॉल करने से ज्यादा नहीं है। हेडर में निजी विधियों के होने का अर्थ है कि सार्वजनिक पद्धति के लिए कॉल निजी विधियों के वास्तविक कोड के लिए पूरी तरह से इनबिल्ड हो सकती है, और निजी पद्धति के लिए कॉल के साथ इनलाइनिंग बंद नहीं होती है। यहां तक ​​कि एक अलग संकलन इकाई से (और सार्वजनिक तरीकों को आमतौर पर विभिन्न संकलन इकाइयों से बुलाया जाएगा)।

बेशक इसका कारण यह भी है कि कंपाइलर ओवरलोड रिज़ॉल्यूशन की समस्याओं का पता नहीं लगा सकता है अगर वह निजी सहित सभी तरीकों को नहीं जानता है।


Inlining के बारे में उत्कृष्ट बिंदु! मुझे लगता है कि यह stdlib और अन्य पुस्तकालयों के लिए विशेष रूप से प्रासंगिक है जिसमें इनलाइन परिभाषित तरीके हैं। (इतना नहीं तो आंतरिक कोड, जहां LTO टीयू सीमाओं के पार लगभग कुछ भी कर सकते हैं के लिए)
underscore_d

0

यह उन कार्यों को निजी सदस्यों तक पहुंचने की अनुमति देता है। अन्यथा आपको friendहेडर में वैसे भी उनकी आवश्यकता होगी ।

यदि कोई भी कार्य वर्ग के निजी सदस्यों तक पहुंच सकता है तो निजी बेकार हो जाएगा।


1
हो सकता है कि मुझे प्रश्न में अधिक स्पष्ट होना चाहिए था - मेरा मतलब था कि भाषा को इस तरह से क्यों बनाया गया है? यह क्यों होना चाहिए या यह डिजाइन एक अच्छा क्यों है?
१४'१
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.