2010-12-20 17 views
41

मान लीजिए कि मेरे पास कक्षा F है जो कक्षा G (वैश्विक नामस्थान में) और C (नामस्थान A में) के लिए मित्र होना चाहिए।सी ++ मित्र वर्ग को केवल अन्य नामस्थानों में आगे की घोषणा की आवश्यकता क्यों है?

  • A::C को दोस्त बनना, F आगे घोषित किया जाना चाहिए।
  • G पर मित्र होने के लिए, F की कोई और घोषणा आवश्यक नहीं है।
  • इसी तरह, एक वर्ग A::BF आगे घोषणा

निम्नलिखित कोड इस दिखाता है और जीसीसी 4.5 के साथ संकलित, कुलपति ++ 10 और कम से कम के साथ एक अन्य संकलक बिना A::C के दोस्त हो सकता है।

class G { 
    friend class F; 
    int g; 
}; 

// without this forward declaration, F can't be friend to A::C 
class F; 

namespace A { 

class C { 
    friend class ::F; 
    friend class BF; 
    int c; 
}; 

class BF { 
public: 
    BF() { c.c = 2; } 
private: 
    C c; 
}; 

} // namespace A 

class F { 
public: 
    F() { g.g = 3; c.c = 2; } 
private: 
    G g; 
    A::C c; 
}; 

int main() 
{ 
    F f; 
} 

मेरे लिए यह असंगत लगता है। क्या इसका कोई कारण है या क्या यह मानक का एक डिज़ाइन निर्णय है?

उत्तर

40

C++ स्टैंडर्ड ISO/IEC 14882:2003(E)

7.3.1.2 नामस्थान सदस्य परिभाषाओं

पैरा 3

हर नाम पहले एक नाम स्थान में घोषित कि नाम स्थान का एक सदस्य है। यदि में कोई मित्र घोषणा पहले गैर-स्थानीय वर्ग कक्षा या फ़ंक्शन (यह दर्शाती है कि वर्ग या फ़ंक्शन का नाम अयोग्य है) मित्र वर्ग या फ़ंक्शन आंतरिक नामांकन नामस्थान का सदस्य है।

// Assume f and g have not yet been defined. 
void h(int); 
template <class T> void f2(T); 
namespace A { 
    class X { 
    friend void f(X); // A::f(X) is a friend 
     class Y { 
     friend void g(); // A::g is a friend 
     friend void h(int); // A::h is a friend 
     // ::h not considered 
     friend void f2<>(int); // ::f2<>(int) is a friend 
     }; 
    }; 
    // A::f, A::g and A::h are not visible here 
    X x; 
    void g() { f(x); } // definition of A::g 
    void f(X) { /* ... */} // definition of A::f 
    void h(int) { /* ... */ } // definition of A::h 
    // A::f, A::g and A::h are visible here and known to be friends 
} 

आपका friend class BF; वैश्विक नामस्थान नाम स्थान से एक नहीं बल्कि में A::BF की घोषणा है। इस नई घोषणा से बचने के लिए आपको वैश्विक पूर्व घोषणा की आवश्यकता है।

+0

+1। –

+9

एक उचित व्यक्ति पूछ सकता है कि "दोस्त वर्ग :: एफ;" "(जैसा कि ओपी के कोड में दिखाया गया है) लिखने के लिए पर्याप्त क्यों नहीं है, इस प्रकार स्पष्ट रूप से 'एफ' को वैश्विक नामस्थान में धक्का दे रहा है। मुझे लगता है कि जवाब "एक योग्य आईडी कभी भी एक नया नाम घोषित नहीं करता है" के आधार पर है, लेकिन मुझे यकीन नहीं है कि इस बिंदु पर मानक क्या कहता है। – zwol

+0

@Zack यह मेरा प्रारंभिक प्रश्न भी था: जब मैं किसी अन्य नामस्थान में कक्षा को स्थानांतरित करता हूं, तो मुझे आगे की घोषणा जोड़ने की आवश्यकता क्यों होती है? लेकिन इस विषय पर पहले से ही कुछ चर्चाएं हैं (उदा। Http://stackoverflow.com/questions/2059665/, http://stackoverflow.com/questions/1368642/)। ऐसा लगता है कि एक ही दायरे में आगे की घोषणा की आवश्यकता नहीं है एक सुविधा है जो मानक के लेखकों द्वारा दी गई है। – pesche

1

क्योंकि यदि आप namespace {} ब्लॉक के अंदर हैं तो वैश्विक नामस्थान में कुछ घोषित करने में सक्षम होने का अर्थ नहीं होगा। friend class BF; का कारण यह है कि यह एक निहित आगे की घोषणा की तरह कार्य करता है।

3

के खाते में अपने नमूना से इन 3 कोड लाइनों लेते हैं:

1. friend class F; // it creates "friend declaration", (that's not the same as ordinary forward declaration 

2. class F; // without this forward declaration, F can't be friend to A::C <-- this is ordinary forward declaration 

3. friend class ::F; // this is qualified lookup (because of ::), so it needs previous declaration, which you provide in line 2. 

सी ++ पैरा 7.3.1.2 में मानक, बिंदु 3 (नामस्थान सदस्य परिभाषाओं) का कहना है:

दोस्त घोषणापत्र स्वयं नाम को अयोग्य लुकअप (3.4.1) या योग्य लुकअप (3.4.3) पर दिखाई नहीं देता है।[नोट: मित्र का नाम इसके नामस्थान में दिखाई देगा यदि मिलान घोषणा नामस्थान स्कोप पर प्रदान की जाती है (या तो कक्षा परिभाषा दोस्ती देने से पहले या बाद में)। -जेंड नोट]

और लाइन 2 वास्तव में मानक की आवश्यकता के अनुसार निम्नानुसार है।

सभी भ्रम इसलिए है क्योंकि "मित्र घोषणा" कमजोर है, आपको आगे के उपयोग के लिए ठोस आगे की घोषणा प्रदान करने की आवश्यकता है। वास्तविक मानक संदर्भ के लिए

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