2016-03-10 4 views
17

कोड की निम्न सरल टुकड़ा संकलित भीतर वर्ग की घोषणा है, हालांकि मुझे समझ नहीं आता क्यों:सी ++ फॉरवर्ड क्लासेस

class C { 
    class B; 

    class A { 
     B getB() { return B(); } 
    }; 

    class B { 
    }; 
}; 

int main(int, char**) 
{ 
    return 0; 
} 

मैं तो "class C" सामान बाहर टिप्पणी करते हैं, तो इतना है कि B के आगे घोषणा , A की परिभाषा और B की परिभाषा अब एक वर्ग के भीतर नेस्ट कर रहे हैं, कोड संकलन नहीं करता, क्योंकि B एक अधूरी प्रकार का है:

main.cpp: In member function 'B A::getB()': 
main.cpp:6: error: return type 'struct B' is incomplete 
main.cpp:6: error: invalid use of incomplete type 'struct B' 
main.cpp:3: error: forward declaration of 'struct B' 

मैं समझ और इसका अर्थ अपूर्ण होने के लिए क्या है, अर्थात् कि इसे अभी तक परिभाषित नहीं किया गया है और इसलिए संकलक संभवतः यह नहीं जानता कि इसके लिए कितना स्थान आवंटित किया जाए। लेकिन B को ऊपर दिए गए कोड में अधूरा क्यों नहीं माना जाता है, जहां A और B दोनों को C के अंदर घोषित और परिभाषित किया गया है?

उत्तर

10

मेरा मानना ​​है कि इस [basic.scope.class] का परिणाम है:

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

class C { 
    class B; // (1) 

    class A { 
     B getB() { 
      return B(); // both (1) and (2) in scope here 
         // since (2) is the complete type declaration, 
         // this is perfectly fine 
     } 
    }; 

    class B { // (2) 
    }; 
}; 

तुलनात्मक रूप से अगर C एक वर्ग के थे एक namespace के बजाय:

है, B की पूर्ण घोषणा की गुंजाइश नेस्टेड वर्ग के सदस्य समारोह के शरीर में शामिल , कक्षा B की पूर्ण घोषणा का दायरा A::getB() में विस्तारित नहीं होगा। एकमात्र दृश्य घोषणा B की अग्रेषित घोषणा होगी जिसे मैंने (1) लेबल किया था - इसलिए B() वहां अपूर्ण प्रकार का निर्माण होगा।

+0

बहुत बढ़िया, इसे साफ़ करने के लिए धन्यवाद। इस विशेष प्रश्न को क्या लाया गया है libpqxx का ['परिणाम'] (http://pqxx.org/devprojects/libpqxx/doc/stable/html/Reference/) वर्ग है, जिसने 'tuple' और' field' कक्षाएं निहित की हैं, में जो 'टुपल' अपने फ़ंक्शन निकायों में से एक में 'फ़ील्ड' बनाता है (यानी, लाइन 183) – villapx

5

मानक यह स्पष्ट करने में स्पष्ट है कि विधि के शरीर को उस वर्ग के बाद व्याख्या किया जाता है जो इसे संलग्न करता है।

इस प्रकार C::A::getB(), A, B और C के शरीर का मूल्यांकन के समय में सभी पूरा प्रकार हैं।

+0

किसी भी मौका आप जानते हैं कि मैं कहाँ मिल सकता है हो सकता है वह शब्दकोष? – villapx

+1

इसे खोजने का प्रयास कर रहा है ... दुर्भाग्यवश, "ड्राफ्ट फ़ंक्शन" शब्द का उल्लेख 2015 ड्राफ्ट मानक पीडीएफ में 582 बार किया गया है ... http://open-std.org/JTC1/SC22/WG21/docs/papers/2015 /n4527.pdf –

9

कक्षा परिभाषा पूरी तरह से संसाधित होने तक इनलाइन सदस्य फ़ंक्शन का शरीर संसाधित नहीं होता है।

इसलिए, आप का उपयोग कर सकते हैं:

class A 
{ 
    class B; 
    B getB() { return B(); } 

    class B {}; 
}; 

कि भी सदस्य चर कि अभी तक इनलाइन सदस्य समारोह परिभाषा में इस्तेमाल किया जाएगा घोषित नहीं कर रहे हैं अनुमति देता है।

class Foo 
{ 
    int getBar() { return bar; } 

    int bar; 
}; 

मैं अनुमान लगा रहा हूँ एक ही तर्क नेस्टेड वर्गों के सदस्य कार्यों की परिभाषा इनलाइन के लिए बढ़ा दिया गया है - यानी वे संसाधित नहीं जब तक युक्त वर्ग परिभाषा पूरी तरह से संसाधित किया जाता है कर रहे हैं।

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

पीएस 2The answer by Barry मानक में संदर्भ है जो प्रश्न में कोड को वैध बनाता है।

+0

आपने मुझे जवाब में हराया। मैं स्टैंडरीज़ खोजने की कोशिश कर रहा था। मुझे लगता है कि यह कथित है * इसी प्रकार नाम लुकअप के दौरान, जब की परिभाषा में उपयोग किया गया एक अयोग्य आईडी (5.1) कक्षा X के लिए एक सदस्य फ़ंक्शन एक स्थिर सदस्य, एक गणक या घोंसला प्रकार के वर्ग एक्स या एक के लिए हल करता है एक्स की बेस क्लास, अयोग्यता आईडी को एक योग्य-आईडी (5.1) में परिवर्तित किया गया है जिसमें नेस्टेड-नाम-विनिर्देशक सदस्य फ़ंक्शन की श्रेणी का नाम है। * ** [class.mfct.non-static] से **। यदि आप आगे बढ़ते हैं और इसका उपयोग करते हैं। – NathanOliver

+0

@NathanOliver मुझे नहीं लगता कि यह सही है। यह सिर्फ इतना कहता है कि 'बी' मिलेगा - लेकिन आगे की घोषणा के कारण 'बी' मिलेगा। मुझे नहीं पता कि सही अनुभाग कहां है, इसे भी नहीं मिला। – Barry

+0

हो सकता है * यदि क्लास एक्स को नेमस्पेस स्कोप में परिभाषित किया गया है, तो क्लास एक्स में एक नेस्टेड क्लास वाई घोषित किया जा सकता है और बाद में कक्षा X की परिभाषा परिभाषित किया गया है या बाद में कक्षा X की परिभाषा को संलग्न करने वाले नामस्थान स्कोप में परिभाषित किया जा सकता है। ** [class.nest] ** – NathanOliver

0

कि इसके अलावा जब मैं नेस्टेड कक्षाएं मैं अपने कोड में कुछ बुरी डिजाइन गंध के लिए करते हैं घोषित अग्रेषित करने के लिए की जरूरत मिल गया है, चाल मैं का उपयोग करें:

// Foo.h 
class Foo { 
    class Bar { 
    }; 
}; 
class Foobar : public Foo::Bar {}; 


// Zoo.h 
/* Fwd declare */ 
class FooBar; 
+0

आप अपना उत्तर संपादित कर सकते हैं – villapx

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