2012-07-17 10 views
29

सी ++ में कक्षाओं को अपने निजी कार्यों की घोषणा क्यों करनी है? क्या यह वास्तविक तकनीकी कारण है (संकलन समय में इसकी भूमिका क्या है) या यह केवल स्थिरता के लिए है?सी ++: निजी कार्यों को क्यों घोषित किया जाना चाहिए?

+0

क्या आप पूछ रहे हैं कि कार्यों को खुद घोषित क्यों किया जाना चाहिए, या आप पूछ रहे हैं कि आपको उन कार्यों के लिए 'निजी' क्यों कहना है? – GManNickG

+0

@GManNickG मुझे लगता है कि पहला। –

+2

@GManNickG पहला एक। मुझे नहीं पता कि मेरे हेडर समेत अन्य वर्गों को अपने निजी कार्यों के बारे में क्यों पता होना चाहिए – Ancurio

उत्तर

21

मैं, पूछा क्यों निजी कार्यों के सभी पर घोषित किया जाना था वे अन्य अनुवाद इकाइयों के लिए कुछ भी (न तो वस्तु के आकार और न ही vtable प्रविष्टि) पता करने के लिए

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

प्रोग्रामर के दृष्टिकोण से, निजी कार्यों की घोषणा अभी भी पूरी तरह से बेकार नहीं है। कल्पना करें कि 2 कक्षाएं हैं, जिनमें से एक friend है। मित्र वर्ग को यह जानने की आवश्यकता होगी कि उस वर्ग के निजी लोग कैसा दिखते हैं, (यह चर्चा अजीब हो रही है) अन्यथा वे इसका उपयोग नहीं कर सकते हैं।

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

एक अंतिम नोट यह है कि, private फ़ंक्शंस vtable आकार को प्रभावित कर सकता है। यही है, अगर वे virtual हैं।


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

यह विशेष रूप से इनलाइन सदस्य कार्य है।

+1

हाँ, मैं स्थिर सी कार्यों का उपयोग करके सी में कार्यान्वयन छुपा रहा हूं, इसलिए मैं बस घोषणा करने की उम्मीद करता था (पहले किसी भी कार्यान्वयन) सीपीपी के अंदर निजी कार्यों को बाकी हिस्सों के अलावा, सी – Ancurio

+0

में स्थिर घोषणाओं की तरह "मित्र" उपयोग केस हालांकि वैध बिंदु है। धन्यवाद। – Ancurio

+0

@ एंकुरियो, भले ही आप जो कहते हैं वह बिल्कुल समझ में आता है, दुर्भाग्य से सी ++ से दो में कक्षा परिभाषा को टुकड़ा करने के लिए कोई समर्थन नहीं है। – Shahbaz

2

पहुंच स्तर दृश्यता को प्रभावित नहीं करता है। निजी कार्यों बाहरी कोड के लिए दिखाई दे रहे हैं और अधिभार संकल्प (जो तब एक पहुँच violoation त्रुटि में परिणाम होगा) द्वारा चुना जा सकता है:

class A { 
    void F(int i) {} 
public: 
    void F(unsigned i) {} 
}; 

int main() { 
    A a; 
    a.F(1); // error, void A::F(int) is private 
} 

भ्रम की कल्पना करें जब यह काम करता है:

class A { 
public: 
    void F(unsigned i) {} 
}; 

int main() { 
    A a; 
    a.F(1); 
} 

// add private F overload to A 
void A::F(int i) {} 

लेकिन यह बदल रहा है पहले कोड में एक अलग फ़ंक्शन का चयन करने के लिए ओवरलोड रिज़ॉल्यूशन का कारण बनता है। और निम्नलिखित उदाहरण के बारे में क्या?

class A { 
public: 
    void F(unsigned i) {} 
}; 

// add private F overload to A 
void A::F(int i) {} 

int main() { 
    A a; 
    a.F(1); 
} 

या यहाँ इस का एक और उदाहरण गलत हो रहा है:

// A.h 
class A { 
public: 
    void g() { f(1); } 
    void f(unsigned); 
}; 

// A_private_interface.h 
class A; 
void A::f(int); 

// A.cpp 
#include "A_private_interface.h" 
#include "A.h" 

void A::f(int) {} 
void A::f(unsigned) {} 

// main.cpp 
#include "A.h" 

int main() { 
    A().g(); 
} 
+0

एह, ऐसा लगता है कि अधिभार नियमों को बदलने की आवश्यकता होगी। – GManNickG

+0

@GManNickG खाते में दृश्यता लेने के लिए और पहुंच योग्य तरीकों का चयन नहीं करें? सी ++ के काम के तरीके के लिए अच्छा कारण है। उदाहरण के लिए: http://stackoverflow.com/questions/644461/c-constructor-overloading-private-and-public – bames53

+0

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

0

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

यदि आपके पास कोई तरीका है जो केवल .cpp फ़ाइल में उपयोग किया जाता है और कक्षा के अन्य निजी सदस्यों तक सीधे पहुंच पर निर्भर नहीं करता है, तो उसे अज्ञात नेमस्पेस पर ले जाने पर विचार करें। फिर, इसे हेडर फ़ाइल में घोषित करने की आवश्यकता नहीं है।

+1

हां, लेकिन _ spehy क्यों कहते हैं कि उन्हें घोषित किया जाना चाहिए_? आपने सवाल का जवाब नहीं दिया। पहले से ही नियम कह रहे हैं कि कॉलिंग से पहले कार्यों को घोषित किया जाना चाहिए, इसलिए यह नहीं है। (नामस्थान टिप हालांकि एक अच्छा है) –

20

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

+9

मुझे लगता है कि आपने अभी पाइथन कक्षाओं का वर्णन किया है =) – JoeFish

0

निजी कारणों को घोषित क्यों किया जाना चाहिए इसके कुछ कारण हैं।

पहले संकलन समय त्रुटि जाँच

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

दूसरा कास्टिंग और विरासत

सी ++ मानक से लिया:

3 [ध्यान दें: एक निजी आधार वर्ग के एक सदस्य सीधे एक विरासत सदस्य नाम के रूप में दुर्गम है, लेकिन सुलभ हो सकता है। पॉइंटर रूपांतरण (4.10) और स्पष्ट कास्ट (5.4) के नियमों के कारण, एक सूचक से एक व्युत्पन्न कक्षा में एक पॉइंटर से एक अपरिवर्तनीय बेस क्लास में एक रूपांतरण हो सकता है यदि एक अंतर्निहित रूपांतरण का उपयोग किया जाता है, लेकिन अच्छी तरह से गठित किया गया है अगर एक स्पष्ट कास्ट का उपयोग किया जाता है।

3 दोस्त

मित्रों को एक दूसरे वहाँ साधारण सैनिक दिखा। एक निजी विधि को किसी अन्य वर्ग द्वारा कॉल किया जा सकता है जो एक दोस्त है।

4 जनरल विवेक और अच्छा डिजाइन

कभी एक और 100 डेवलपर्स के साथ एक परियोजना पर काम किया। एक मानक और नियम का एक सामान्य सेट रखने के लिए बनाए रखने में मदद करता है। कुछ निजी घोषित करने से समूह में हर किसी के लिए एक विशिष्ट अर्थ होता है।

यह भी अच्छा ओओ डिजाइन सिद्धांतों में बहता है। क्या पर्दाफाश करने के लिए और क्या नहीं

+3

यह नहीं चाहता कि Ancurio जानना चाहता है। वह आश्चर्य करता है कि क्यों हम (कुछ) निजी कार्यों को पहले * एक * गुप्त * के रूप में नहीं रख सकते हैं। आप उस फ़ंक्शन को कॉल नहीं कर सकते जिसे आप नहीं जानते हैं। –

+0

संकलक को यह पता होना चाहिए कि यह निजी है। इसलिए जब कोई और इसे कॉल करने का प्रयास करता है तो यह संकलन समय चेतावनी निकाल सकता है ... कुछ भी सचमुच सच नहीं है –

+1

@nate_weldon यह सच है, लेकिन यदि सार्वजनिक गैर-वर्चुअल फ़ंक्शंस को सार्वजनिक हेडर फ़ाइल में घोषित नहीं किया गया था (और इसलिए प्रलेखन) पहली जगह में, कोई भी इसे कॉल करने का प्रयास नहीं करेगा। शायद अपने लिए छोड़कर ... किस मामले में चेतावनी (क्या यह वास्तव में कोई त्रुटि नहीं है?) समझ में आता है। – Ancurio

3

चिंताओं का एक संयोजन नहीं है, लेकिन:

  • सी ++ आप फिर से खुल एक वर्ग अपनी प्रारंभिक परिभाषा के बाद उस में नए सदस्यों की घोषणा करने नहीं देता।
  • सी ++ आपको विभिन्न अनुवाद इकाइयों में एक वर्ग की अलग-अलग परिभाषाएं नहीं देता है जो प्रोग्राम बनाने के लिए गठबंधन करते हैं।

इसलिए:

  • किसी भी निजी सदस्य कार्यों कि .cpp फ़ाइल वर्ग में घोषित चाहता है ज फ़ाइल है, जो वर्ग के हर उपयोगकर्ता भी देखता है के रूप में परिभाषित किया जाना चाहिए।

व्यावहारिक दोहरी संगतता की पीओवी से: के रूप में डेविड ने एक टिप्पणी में कहते हैं, निजी virtual कार्यों आकार और इस वर्ग के vtable के लेआउट और किसी भी कक्षा है कि यह एक आधार के रूप में उपयोग प्रभावित करते हैं। तो संकलक को उन कोडों को संकलित करते समय भी उनके बारे में जानना आवश्यक है जो उन्हें कॉल नहीं कर सकते हैं।

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

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

आखिरकार यह नीचे आ सकता है, "डिजाइनर इसे इस तरह से चाहते थे", या ऐसा हो सकता है कि किसी ने इसे आजमाया और उस बाधा का सामना किया जिसे मैंने नहीं सोचा था।

+0

वर्तमान मॉड्यूल प्रस्तावों में गोपनीयता समस्या का समाधान होता है, क्योंकि वे दृश्यता का एक और "परत" या "कमरा" जोड़ते हैं: कक्षा स्वयं, मॉड्यूल, "बाहरी कोड"। 'निजी' बस मॉड्यूल परिभाषा के बाहर रिसाव नहीं करेगा, और संकलक अभी भी सब कुछ के बारे में पता कर सकते हैं। – Xeo

+0

"_C++ आपको प्रारंभिक परिभाषा के बाद इसमें नए सदस्यों को घोषित करने के लिए कक्षा को दोबारा खोलने नहीं देता है ._" यह सही नहीं है: 14.7.3 ** स्पष्ट विशेषज्ञता ** '[temp.expl.spec]' " निम्न में से किसी एक का स्पष्ट विशेषज्ञता: (...) - कक्षा या वर्ग टेम्पलेट का सदस्य वर्ग टेम्पलेट - किसी वर्ग या कक्षा टेम्पलेट के सदस्य फ़ंक्शन टेम्पलेट को घोषणा (...) "" द्वारा घोषित किया जा सकता है विशिष्ट टेम्पलेट को निर्दिष्ट नामस्थान में स्पष्ट विशेषज्ञता घोषित की जाएगी। " – curiousguy

+0

@curiousguy: सुनिश्चित नहीं है कि मैं आपका अनुसरण करता हूं। मुझे नहीं लगता कि सदस्य टेम्पलेट का विशेषज्ञता एक "नया सदस्य" है, क्योंकि टेम्पलेट सदस्य है। शायद मैं गलत हो सकता हूँ। यदि मैं गलत हूं तो निश्चित रूप से टेम्पलेट्स जो मैं कह रहा था, उसका अपवाद है, साथ ही कक्षा के बाहर सदस्य टेम्पलेट्स को विशेषज्ञता देने के साथ ही आप कक्षा के बाहर * तत्काल * सदस्य टेम्पलेट्स भी कर सकते हैं। किसी भी मामले में मुझे नहीं लगता कि कक्षा "पुनः खोला गया" है, और मुझे नहीं लगता कि यह प्रश्नकर्ता की मदद करता है। –

1

एक कारण यह है कि सी ++ दोस्तों में आपके निजी लोगों तक पहुंच सकते हैं। दोस्तों के लिए उन्हें एक्सेस करने के लिए, दोस्तों को उनके बारे में पता होना चाहिए।

+0

@Neal: ठीक है ... यह 'दोस्त' का friggin * उद्देश्य * है। – Xeo

संबंधित मुद्दे

 संबंधित मुद्दे