2011-09-07 13 views
5

नीचे वर्गों को देखते हुए दो अलग-अलग हेडर फाइल में हैं और किसी भी क्रम में दिखाई दे सकता है:सी ++ कक्षाएं प्रोटोटाइप संघर्ष

//TestB.h 
class TestB; //Forward declaration for a later operator= in a centralised header 

class TestA 
{ 
    const TestA&operator=(const TestB); //defined in Test.h 
}; 

और:

//TestA.h 
class TestA; //Forward declaration for a later operator= in a centralised heaer 

class TestB 
{ 
    const TestB&operator=(const TestA); //defined in Test.h 
}; 

मैं प्रोटोटाइप संघर्ष से कैसे बच सकता हूँ?

सहायता की सराहना की जाती है।

मैं बिल्कुल हर किसी से क्षमा चाहता हूं! मैं वहां संदर्भ के लिए इरादा रखता था (ऑपरेटर = तर्कों में एम्पर्सेंड - मैं कभी भी बार साधारण पीओडी की प्रतिलिपि बनाकर पास नहीं होता) और इसका मतलब केवल प्रोटोटाइप विवादों के बारे में प्रश्न था! मुझे लगता है कि यह सबूत पढ़ने के महत्व को दिखाने के लिए चला जाता है! मैंने मूल (मेरा गलत) संदर्भ दिए गए उत्तर को स्वीकार कर लिया है।

मैं केवल कुछ ही मिनटों के लिए ही दूर हो गया था और गलती से अवगत नहीं था!

+1

आपका क्या मतलब है "प्रोटोटाइप संघर्ष"? –

+2

यहां कुछ भी गलत नहीं है - यह ठीक काम करेगा। आपको त्रुटि को बेहतर तरीके से और वास्तविक कोड के साथ समझाएंगे। –

+1

@ एएलएस: आप मूल्य से अपूर्ण प्रकार ले रहे कार्यों की घोषणा कर सकते हैं; आप टाइप की परिभाषा के बाद तक उन्हें परिभाषित या कॉल नहीं कर सकते हैं। –

उत्तर

4

आप कक्षाओं के पैरामीटर के रूप में संदर्भ पास करते हैं। इस तरह, एक वर्ग और उसके सदस्य कार्यों को दूसरे के बारे में जानने के बिना घोषित किया जा सकता है।

//TestB.h 
class TestB; //Forward declaration for a later operator= in a centralised header 

class TestA 
{ 
    const TestA&operator=(const TestB &); //defined in TestB.h 
}; 

और:

//TestA.h 
class TestA; //Forward declaration for a later operator= in a centralised heaer 

class TestB 
{ 
    const TestB&operator=(const TestA *); //defined in TestA.h 
}; 

इस के बाद, आप इन सदस्य परिभाषित करने के लिए सक्षम होने के लिए दोनों TestA.h और TestB.h दोनों TestA.cpp और TestB.cpp फाइलों में शामिल करने के लिए होगा कार्य करता है।

+0

अर्थशास्त्र को बदलने की कोई आवश्यकता नहीं है, आप ** उन कार्यों को घोषित कर सकते हैं जो * अपूर्ण प्रकार * को मानते हैं या जब तक आप * परिभाषित करने की कोशिश नहीं करते हैं * * उन कार्यों को कॉल करें। –

4

मेरा मूल उत्तर पूरी तरह से गलत लगता है।

जांचें कि आपने अपने सभी शीर्षलेख फ़ाइलों में गार्ड शामिल किए हैं ताकि आप अनंत समावेशन श्रृंखला के साथ समाप्त न हों। फिर प्रत्येक कार्यान्वयन में हेडर में शामिल हैं:

// A.cpp 
#include "A.h" 
#include "B.h" // for complete type TestB 

const TestA & TestA::operator=(const TestB) { /* ... */ } 

// B.cpp 
#include "B.h" 
#include "A.h" // for complete type TestA 

const TestB & TestB::operator=(const TestA) { /* ... */ } 

कृपया ध्यान दें कि इस तरह के एक निर्माण उत्सुक डिजाइन स्थिति पैदा करता है जहां या तो TestA या TestB के किसी भी उपभोक्ता जो ऑपरेटर हमेशा शामिल करना चाहिए कॉल करने के लिए कामना की A.h और B.h दोनों, जो बहुत दानेदार है, लेकिन थोड़ा अप्रत्याशित भी है। यह क्लाइंट द्वारा उपयोग के लिए एक इंटरमीडिएट हेडर फ़ाइल जोड़ना फायदेमंद हो सकता है जिसमें हेडर फाइलें शामिल हैं, या हेडर फाइलों में पारस्परिक समावेश (गार्ड के साथ!) जोड़ने के लिए।


आप जिस तरह से आप यह लिखा में इसके समाधान नहीं कर सकते, क्योंकि आप एक खुले दिल से पुनरावर्ती अनंत निर्भरता है।

जिस तरह से आप आम तौर पर इस संदर्भ द्वारा बजाय प्रतिलिपि द्वारा तर्क पारित करने के लिए संदर्भ से गुजर के बाद से है नहीं पूरा प्रकार के ज्ञान की आवश्यकता होती है:

const TestA & operator=(const TestB &); 
            ^^^^^ 
            vvvvv 
const TestB & operator=(const TestA &); 

+2

तर्क प्रकार अधूरा होने पर भी आप मान द्वारा तर्क लेते हुए कार्यों की घोषणा कर सकते हैं। कक्षा परिभाषा के बाद तक आप फ़ंक्शन को परिभाषित नहीं कर सकते हैं। –

+0

@ माइक: मैं आश्चर्यचकित हूं, मैंने वास्तव में सोचा कि इसकी अनुमति नहीं थी! –

+0

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

0

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

1

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

वहाँ एक आम धारणा है कि आप कुछ भी है कि एक आगे घोषित प्रकार के मूल्य तरह लग रहा है उपयोग नहीं कर सकते है, तथ्य यह है कि आप उस प्रकार के वस्तुओं नहीं बना सकते हैं या उस प्रकार के सदस्य चर बना सकते हैं, लेकिन आप है उन कार्यों को घोषित कर सकता है जो मूल्य द्वारा लेते हैं या वापस करते हैं।

आप नहीं, दूसरे हाथ पर, , परिभाषित कर सकते हैं या कॉल उन कार्यों के बाद से है कि अधूरा प्रकार का ऑब्जेक्ट के निर्माण की आवश्यकता होगी।

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