2009-04-30 3 views
183

में टाइपिफ़ की अग्रेषित घोषणा क्यों संकलक ने मुझे टाइपिफ़ को घोषित करने की अनुमति नहीं दी?सी ++

मानना ​​असंभव है, मेरे शामिल पेड़ को छोटा रखने के लिए सबसे अच्छा अभ्यास क्या है?

उत्तर

12

एक प्रकार की घोषणा करने के कारण, इसका आकार ज्ञात होना चाहिए। आप टाइप करने के लिए एक पॉइंटर घोषित कर सकते हैं, या प्रकार के पॉइंटर को टाइप कर सकते हैं।

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

संपादित करें: j_random_hacker इस जवाब देने के लिए एक महत्वपूर्ण योग्यता कहते हैं, आकार की जरूरत है मूल रूप से है कि उपयोग प्रकार पता किया जाना है, लेकिन एक आगे घोषणा करता है, तो हम केवल प्रकार मौजूद पता करने की जरूरत बनाया जा सकता है, में प्रकार के पॉइंटर्स या संदर्भ बनाने के लिए आदेश। चूंकि ओपी ने कोड नहीं दिखाया, लेकिन शिकायत की कि यह संकलित नहीं होगा, मैंने माना (शायद सही ढंग से) कि ओपी प्रकार का उपयोग करने की कोशिश कर रहा था, न कि इसे संदर्भित करें।

+30

खैर, वर्ग प्रकार के आगे घोषणाओं उनके आकार के ज्ञान के बिना इन प्रकार की घोषणा। साथ ही, इस तरह के अधूरे प्रकारों के पॉइंटर्स और संदर्भों को परिभाषित करने में सक्षम होने के अलावा, कार्यों को घोषित किया जा सकता है (लेकिन परिभाषित नहीं किया गया) जो पैरामीटर लेते हैं और/या इस प्रकार के मान को वापस करते हैं। –

+3

क्षमा करें मुझे नहीं लगता कि यह एक अच्छी धारणा है। यह जवाब बिंदु के बगल में है। टाइपिफ़ को आगे की घोषणा के मामले में यह बहुत अधिक है। अंत में – Cookie

143

आप टाइपपीफ आगे कर सकते हैं। लेकिन

typedef A B; 

करने के लिए आपको सबसे पहले आगे की घोषणा करनी चाहिए A:

class A; 

typedef A B; 
+8

+1 क्योंकि आप तकनीकी रूप से "फॉरवर्ड-टाइपिफ़" नहीं कर सकते हैं (यानी आप "टाइपिफ़ ए" नहीं लिख सकते हैं), आप लगभग निश्चित रूप से पूरा कर सकते हैं कि ओपी ऊपर की अपनी चाल का उपयोग करके क्या हासिल करना चाहता है। –

+8

लेकिन सावधान रहें, अगर टाइपिफ़ बदलता है तो आप उन सभी आगे की घोषणाओं को भी बदल सकते हैं, जो पुराने और नए टाइपपीफ को एक ही इंटरफ़ेस वाले प्रकारों का उपयोग करते हुए याद कर सकते हैं। – math

+10

यह templated कक्षाओं के साथ खुशी से काम नहीं करता है। – Alex

15

C++ (लेकिन सादा सी), यह एक प्रकार दो बार typedef के लिए, जब तक कि दोनों परिभाषाओं पूरी तरह से कर रहे हैं पूरी तरह से कानूनी है समान:

// foo.h 
struct A{}; 
typedef A *PA; 

// bar.h 
struct A; // forward declare A 
typedef A *PA; 
void func(PA x); 

// baz.cc 
#include "bar.h" 
#include "foo.h" 
// We've now included the definition for PA twice, but it's ok since they're the same 
... 
A x; 
func(&x); 
+29

रखरखाव संख्या सं। इस तरह की चीज आपको जल्दी या बाद में केस्टर में काट देगी। –

+1

@ मार्कस्टोरर, कम से कम संकलक किसी भी अंतर को पकड़ लेगा और एक त्रुटि उत्पन्न करेगा। मैंने इसे दृश्य सी ++ के साथ सत्यापित किया। – Alan

+0

अच्छा, लेकिन परिभाषा के अनुसार 'ए' खाली होने के बाद से आप इस तरह से 'ए' फ़ील्ड को कैसे परिभाषित करते हैं? –

41

आप में से उन लोगों के लिए मुझे पसंद है, जो एक सी शैली struct कि typede का उपयोग कर परिभाषित किया गया था की घोषणा को अग्रेषित करने के लिए देख रहे हैं च, कुछ C++ कोड में, मैं एक समाधान इस प्रकार है कि ...

// a.h 
typedef struct _bah { 
    int a; 
    int b; 
} bah; 

// b.h 
struct _bah; 
typedef _bah bah; 

class foo { 
    foo(bah * b); 
    foo(bah b); 
    bah * mBah; 
}; 

// b.cpp 
#include "b.h" 
#include "a.h" 

foo::foo(bah * b) { 
    mBah = b; 
} 

foo::foo(bah b) { 
    mBah = &b; 
} 
+1

प्रगतिवाद के लिए +1 – Travis

+0

@LittleJohn इस समाधान के साथ समस्या यह है कि डमी नाम _bah को सार्वजनिक एपीआई के हिस्से के रूप में नहीं माना जाता है। आगे की डेलकेयर फ़ाइल देखें। – user877329

10

"FWD एक typedef घोषित" करने के लिए आप एक वर्ग या एक struct की घोषणा अग्रेषित करने के लिए और फिर आप घोषित typedef कर सकते हैं प्रकार की जरूरत मिल गया है । कंपाइलर द्वारा एकाधिक समान टाइपिफ स्वीकार्य हैं।

लंबी फ़ार्म:

class MyClass; 
typedef MyClass myclass_t; 

संक्षिप्त रूप:

typedef class MyClass myclass_t; 
6

आगे घोषणाओं का उपयोग करने के बजाय एक पूर्ण #include के तभी संभव है जब आप नहीं हैं प्रकार खुद के प्रयोग पर इरादा (इस फ़ाइल के दायरे में) लेकिन एक सूचक या इसके संदर्भ में।

प्रकार का उपयोग करने के लिए, कंपाइलर को अपना आकार पता होना चाहिए - इसलिए इसकी पूर्ण घोषणा देखी जानी चाहिए - इसलिए एक पूर्ण #include आवश्यक है।

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

दिलचस्प है, जब class या struct प्रकार के सूचक या संदर्भ का उपयोग करते हुए, संकलक अधूरा प्रकार संभाल कर सकते हैं आप की जरूरत बचत के साथ-साथ pointee प्रकार की घोषणा अग्रेषित करने के लिए:

// header.h 

// Look Ma! No forward declarations! 
typedef class A* APtr; // class A is an incomplete type - no fwd. decl. anywhere 
typedef class A& ARef; 

typedef struct B* BPtr; // struct B is an incomplete type - no fwd. decl. anywhere 
typedef struct B& BRef; 

// Using the name without the class/struct specifier requires fwd. decl. the type itself.  
class C;   // fwd. decl. type 
typedef C* CPtr; // no class/struct specifier 
typedef C& CRef; // no class/struct specifier 

struct D;  // fwd. decl. type 
typedef D* DPtr; // no class/struct specifier 
typedef D& DRef; // no class/struct specifier 
1

मैं एक ही मुद्दा था , विभिन्न फाइलों में कई typedefs साथ गड़बड़ नहीं करना चाहता था, इसलिए मैं विरासत के साथ इसका समाधान नहीं:

था:

class BurstBoss { 

public: 

    typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with... 

किया:

class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool> 
{ 

public: 

    ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) { 
    }; 
}; 

एक आकर्षण की तरह काम किया। बेशक, मैं बस

ParticleSystem 
0

के रूप में बिल Kotsias बताया गया है, केवल उचित तरीका निजी अपनी बात की typedef विवरण रखने के लिए के लिए

BurstBoss::ParticleSystem 

से किसी भी संदर्भ बदल सकते हैं और आगे की घोषणा उन्हें करना पड़ा है विरासत के साथ। हालांकि आप इसे C++ 11 के साथ थोड़ा सा कर सकते हैं। इस पर विचार करें:

// LibraryPublicHeader.h 

class Implementation; 

class Library 
{ 
... 
private: 
    Implementation* impl; 
}; 
// LibraryPrivateImplementation.cpp 

// This annoyingly does not work: 
// 
//  typedef std::shared_ptr<Foo> Implementation; 

// However this does, and is almost as good. 
class Implementation : public std::shared_ptr<Foo> 
{ 
public: 
    // C++11 allows us to easily copy all the constructors. 
    using shared_ptr::shared_ptr; 
};