मैं निजी प्रकार पर ऑटो का उपयोग क्यों कर सकता हूं?


139

मुझे किसी तरह आश्चर्य हुआ कि निम्नलिखित कोड संकलित करता है और चलता है (vc2012 और gcc4.7.2)

class Foo {
    struct Bar { int i; };
public:
    Bar Baz() { return Bar(); }
};

int main() {
    Foo f;
    // Foo::Bar b = f.Baz();  // error
    auto b = f.Baz();         // ok
    std::cout << b.i;
}

क्या यह सही है कि यह कोड ठीक संकलित करता है? और यह सही क्यों है? मैं autoएक निजी प्रकार का उपयोग क्यों कर सकता हूं , जबकि मैं इसके नाम का उपयोग नहीं कर सकता (उम्मीद के मुताबिक)?


11
निरीक्षण करें कि f.Baz().iजैसा भी है ठीक है std::cout << typeid(f.Baz()).name()। कक्षा के बाहर का कोड Baz()आपके द्वारा दिए गए प्रकार को "देख" सकता है यदि आप इसे पकड़ सकते हैं, तो आप इसे नाम नहीं दे सकते।
स्टीव जेसप

2
और अगर आपको लगता है कि यह अजीब है (जो आप शायद करते हैं, जैसा कि आप इसके बारे में पूछ रहे हैं) तो आप केवल एक ही नहीं हैं;) यह रणनीति सुरक्षित-बूल मुहावरे जैसी चीजों के लिए शक्तिशाली उपयोगी है, हालांकि।
मैथ्यू एम।

2
मुझे लगता है कि याद रखने वाली बात यह है कि privateएपीआई का वर्णन करने के लिए एक सुविधा के रूप में है कि कंपाइलर लागू करने में मदद कर सकता है। इसका उद्देश्य Barउपयोगकर्ताओं द्वारा प्रकार तक पहुंच को रोकना नहीं है Foo, इसलिए यह Fooकिसी भी तरह से उस उदाहरण की वापसी से किसी भी तरह से बाधा नहीं डालता है Bar
स्टीव जेसोप

1
"क्या यह सही है कि यह कोड ठीक संकलन करता है?" नहीं, आप की जरूरत है #include <iostream>। ;-)
LF

जवाबों:


113

autoअधिकांश भाग के लिए, टेम्पलेट प्रकार में कटौती के लिए नियम समान हैं। उदाहरण पोस्ट उसी कार्य के लिए काम करता है जिस पर आप निजी प्रकार की वस्तुओं को टेम्पलेट फ़ंक्शंस में पास कर सकते हैं:

template <typename T>
void fun(T t) {}

int main() {
    Foo f;
    fun(f.Baz());         // ok
}

और हम निजी प्रकार की वस्तुओं को टेम्पलेट फ़ंक्शंस में क्यों पास कर सकते हैं, आप पूछें? क्योंकि केवल प्रकार का नाम ही दुर्गम है। प्रकार स्वयं अभी भी प्रयोग करने योग्य है, यही कारण है कि आप इसे क्लाइंट कोड में बिल्कुल वापस कर सकते हैं।


32
और यह देखने के लिए कि नाम की गोपनीयता का प्रकार से कोई लेना-देना नहीं है , प्रश्न में public: typedef Bar return_type_from_Baz;कक्षा Fooमें जोड़ें । अब वर्ग के निजी अनुभाग में परिभाषित होने के बावजूद, सार्वजनिक नाम से इस प्रकार की पहचान की जा सकती है।
स्टीव जेसोप

1
@ स्टीव की बात को दोहराने के लिए: नाम के लिए एक्सेस स्पेसियर का इसके प्रकार से कोई लेना-देना नहीं private: typedef Bar return_type_from_Baz;है Foo, जैसा कि प्रदर्शन के अनुसार जोड़कर देखा जाता हैtypedefडी पहचानकर्ता, सार्वजनिक और निजी लोगों तक पहुँचने के लिए बेखबर हैं।
डेमियनह

त्रि - आयामी यह बेमतलब का लगता है। नाम प्रकार के केवल वास्तविक प्रकार के लिए एक उपनाम है। अगर मैं इसे बुलाऊं Barया क्या फर्क पड़ता है SomeDeducedType? ऐसा नहीं है कि मैं इसका इस्तेमाल निजी सदस्यों class Fooया किसी भी चीज़ के लिए कर सकता हूँ।
ईनपोकलम

107

अभिगम नियंत्रण नामों पर लागू होता है । इस उदाहरण की तुलना मानक से करें:

class A {
  class B { };
public:
  typedef B BB;
};

void f() {
  A::BB x; // OK, typedef name A::BB is public
  A::B y; // access error, A::B is private
}

12

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

मैं सिर्फ हैरी पॉटर सादृश्य के साथ एक सवाल का जवाब देने का अवसर नहीं दे सकता:

class Wizard
{
private:
    class LordVoldemort
    {
        void avada_kedavra()
        {
            // scary stuff
        }
    };
public:
    using HeWhoMustNotBeNamed = LordVoldemort;

    friend class Harry;
};

class Harry : Wizard
{
public:
    Wizard::LordVoldemort;
};

int main()
{
    Wizard::HeWhoMustNotBeNamed tom; // OK
    // Wizard::LordVoldemort not_allowed; // Not OK
    Harry::LordVoldemort im_not_scared; // OK
    return 0;
}

https://ideone.com/I5q7gw

हैरी लोफोल की याद दिलाने के लिए क्वेंटिन को धन्यवाद।


5
friend class Harry;वहाँ एक लापता नहीं है ?
क्वेंटिन

@ क्वेंटिन आप बिल्कुल सही हैं! पूर्णता के लिए एक को शायद जोड़ना भी चाहिए friend class Dumbledore;;)
जेपीएचएल

हैरी यह नहीं दिखाता है कि Wizard::LordVoldemort;आधुनिक सी ++ में कॉल करने से वह डरता नहीं है। इसके बजाय, वह फोन करता है using Wizard::LordVoldemort;। (वोल्डेमॉर्ट का ईमानदारी से इस्तेमाल करना इतना स्वाभाविक नहीं है। ;-)
LF

8

अन्य (अच्छे) उत्तरों में जोड़ने के लिए, यहाँ C ++ 98 से एक उदाहरण दिया गया है जो बताता है कि इस मुद्दे को वास्तव autoमें सभी के साथ नहीं करना है

class Foo {
  struct Bar { int i; };
public:
  Bar Baz() { return Bar(); }
  void Qaz(Bar) {}
};

int main() {
  Foo f;
  f.Qaz(f.Baz()); // Ok
  // Foo::Bar x = f.Baz();
  // f.Qaz(x);
  // Error: error: ‘struct Foo::Bar’ is private
}

निजी प्रकार का उपयोग करना निषिद्ध नहीं है, यह केवल प्रकार का नामकरण कर रहा है। उदाहरण के लिए, C ++ के सभी संस्करणों में, उस प्रकार का एक अस्थायी अस्थायी बनाना ठीक है।

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