जवाबों:
C ++ में, केवल एक सूक्ष्म अंतर है। यह C से होल्डओवर है, जिसमें इससे फर्क पड़ता है।
C भाषा मानक ( C89 §3.1.2.3 , C99 .26.2.3 , और C11 §6.2.3 ) पहचानकर्ताओं की विभिन्न श्रेणियों के लिए अलग-अलग नेमस्पेस अनिवार्य करता है, जिसमें टैग आइडेंटिफ़ायर ( struct
/ union
/ enum
) और सामान्य पहचानकर्ता (के लिए typedef
और अन्य पहचानकर्ता) शामिल हैं ।
अगर आपने अभी कहा:
struct Foo { ... };
Foo x;
आपको संकलक त्रुटि मिलेगी, क्योंकि Foo
केवल टैग नामस्थान में परिभाषित किया गया है।
आपको इसे घोषित करना होगा:
struct Foo x;
जब भी आप किसी को संदर्भित करना चाहते हैं Foo
, तो आपको हमेशा इसे कॉल करना होगा struct Foo
। यह तेजी से कष्टप्रद हो जाता है, इसलिए आप एक जोड़ सकते हैं typedef
:
struct Foo { ... };
typedef struct Foo Foo;
अब struct Foo
(टैग नेमस्पेस में) और सिर्फ प्लेन Foo
(साधारण आइडेंटिफ़ायर नेमस्पेस में) दोनों एक ही चीज़ को संदर्भित करते हैं, और आप कीवर्ड के Foo
बिना स्वतंत्र रूप से टाइप की वस्तुओं की घोषणा कर सकते हैं struct
।
निर्माण:
typedef struct Foo { ... } Foo;
सिर्फ घोषणा और के लिए एक संक्षिप्त नाम है typedef
।
आखिरकार,
typedef struct { ... } Foo;
एक अनाम संरचना की घोषणा करता है और typedef
इसके लिए बनाता है । इस प्रकार, इस निर्माण के साथ, यह टैग नेमस्पेस में एक नाम नहीं है, केवल टाइप किए गए नेमस्पेस में एक नाम है। इसका मतलब यह है कि इसे आगे भी घोषित नहीं किया जा सकता है। यदि आप आगे की घोषणा करना चाहते हैं, तो आपको इसे टैग नाम स्थान में एक नाम देना होगा ।
C ++ में, सभी struct
/ union
/ enum
/ class
घोषणाएँ ऐसे कार्य करती हैं जैसे कि वे अंतर्निहित typedef
रूप से संपादित हों, जब तक कि नाम उसी नाम के साथ किसी अन्य घोषणा द्वारा छिपा न हो। देखें माइकल बर्र के जवाब में पूरी जानकारी के लिए।
में इस DDJ लेख , दान साक्स एक छोटा सा क्षेत्र है जहां कीड़े के माध्यम से रेंगना कर सकते हैं अगर आप अपने structs typedef नहीं बताते हैं (और वर्गों!):
यदि आप चाहते हैं, तो आप कल्पना कर सकते हैं कि C ++ हर टैग नाम के लिए एक टाइपिडेफ़ उत्पन्न करता है, जैसे कि
typedef class string string;
दुर्भाग्य से, यह पूरी तरह से सही नहीं है। काश यह इतना आसान होता, लेकिन ऐसा नहीं है। C ++ असंगतताओं को प्रस्तुत किए बिना स्ट्रक्चर्स, यूनियनों, या एनमों के लिए इस तरह के टाइपफेड उत्पन्न नहीं कर सकता है।
उदाहरण के लिए, मान लीजिए कि एक C प्रोग्राम एक फ़ंक्शन और एक स्ट्रक्चर नामित स्थिति दोनों घोषित करता है:
int status(); struct status;
फिर, यह बुरा अभ्यास हो सकता है, लेकिन यह सी है। इस कार्यक्रम में, स्थिति (स्वयं के द्वारा) फ़ंक्शन को संदर्भित करता है; संरचना की स्थिति प्रकार को संदर्भित करती है।
यदि C ++ ने टैग्स के लिए स्वचालित रूप से टाइपराइफ उत्पन्न किया है, तो जब आप इस प्रोग्राम को C ++ के रूप में संकलित करते हैं, तो कंपाइलर उत्पन्न होगा:
typedef struct status status;
दुर्भाग्य से, इस प्रकार का नाम फ़ंक्शन नाम के साथ विरोध करेगा, और प्रोग्राम संकलित नहीं करेगा। इसीलिए C ++ प्रत्येक टैग के लिए केवल एक टाइफाइड उत्पन्न नहीं कर सकता है।
C ++ में, टैग केवल टाइप किए गए नामों की तरह कार्य करते हैं, सिवाय इसके कि कोई प्रोग्राम किसी ऑब्जेक्ट, फ़ंक्शन या एनुमर को उसी नाम और एक टैग के समान स्कोप के साथ घोषित कर सकता है। उस स्थिति में, ऑब्जेक्ट, फ़ंक्शन, या एन्यूमरेटर नाम टैग नाम छुपाता है। प्रोग्राम केवल टैग नाम के सामने कीवर्ड वर्ग, संरचना, संघ, या एनम (उपयुक्त के रूप में) का उपयोग करके टैग नाम को संदर्भित कर सकता है। एक प्रकार का नाम जिसमें इन टैगों में से एक टैग शामिल है, एक विस्तृत प्रकार-विशेष है। उदाहरण के लिए, संरचना की स्थिति और enum महीने विस्तृत प्रकार के विनिर्देशक हैं।
इस प्रकार, एक सी प्रोग्राम जिसमें दोनों शामिल हैं:
int status(); struct status;
C ++ के रूप में संकलित होने पर समान व्यवहार करता है। अकेले नाम की स्थिति फ़ंक्शन को संदर्भित करती है। कार्यक्रम केवल विस्तृत-प्रकार-निर्दिष्ट संरचना स्थिति का उपयोग करके प्रकार को संदर्भित कर सकता है।
तो यह कैसे कीड़ों को कार्यक्रमों में रेंगने की अनुमति देता है? लिस्टिंग 1 में कार्यक्रम पर विचार करें । यह प्रोग्राम एक डिफॉल्ट कंस्ट्रक्टर के साथ एक क्लास फू को परिभाषित करता है, और एक कन्वर्जन ऑपरेटर जो एक फयू ऑब्जेक्ट को चार कॉन्स्ट * में बदलता है। भाव
p = foo();
मुख्य में एक फू वस्तु का निर्माण करना चाहिए और रूपांतरण ऑपरेटर को लागू करना चाहिए। बाद का आउटपुट स्टेटमेंट
cout << p << '\n';
वर्ग फू प्रदर्शित करना चाहिए, लेकिन यह नहीं है। यह फंक्शन फू को प्रदर्शित करता है।
यह आश्चर्यजनक परिणाम तब होता है क्योंकि कार्यक्रम में शीर्षलेख lib.h शामिल होता है जिसे लिस्टिंग 2 में दिखाया गया है । यह हेडर एक फ़ंक्शन को परिभाषित करता है जिसे फू भी कहा जाता है। फ़ंक्शन का नाम foo वर्ग का नाम foo छुपाता है, इसलिए मुख्य रूप से foo का संदर्भ फ़ंक्शन को संदर्भित करता है, न कि क्लास को। मुख्य वर्ग का उल्लेख केवल एक विस्तृत-प्रकार-विनिर्देशक का उपयोग करके कर सकता है, जैसे कि
p = class foo();
पूरे कार्यक्रम में इस तरह के भ्रम से बचने का तरीका वर्ग नाम फू के लिए निम्नलिखित टाइपफेड जोड़ना है:
typedef class foo foo;
कक्षा की परिभाषा से पहले या बाद में। यह टाइपफ़ाइफ़, प्रकार नाम फू और फ़ंक्शन नाम फू (लाइब्रेरी से) के बीच टकराव का कारण बनता है जो एक संकलन-समय त्रुटि को ट्रिगर करेगा।
मैं ऐसे किसी व्यक्ति के बारे में नहीं जानता जो वास्तव में इन टाईपडेफ़्स को पाठ्यक्रम के रूप में लिखता है। इसके लिए बहुत अनुशासन की जरूरत होती है। चूंकि लिस्टिंग 1 में त्रुटियों की घटना संभवतः बहुत छोटी है, इसलिए आप बहुत से इस समस्या से कभी नहीं बचते हैं। लेकिन अगर आपके सॉफ़्टवेयर में कोई त्रुटि शारीरिक चोट का कारण बन सकती है, तो आपको लिखना चाहिए कि कोई त्रुटि नहीं होने की स्थिति में कोई बात नहीं है।
मैं कल्पना नहीं कर सकता कि कोई भी वर्ग के नाम को किसी फ़ंक्शन या ऑब्जेक्ट नाम के साथ वर्ग के समान दायरे में क्यों छिपाना चाहेगा। सी में छिपने के नियम एक गलती थे, और उन्हें सी ++ में कक्षाओं तक नहीं बढ़ाया जाना चाहिए था। वास्तव में, आप गलती को सुधार सकते हैं, लेकिन इसके लिए अतिरिक्त प्रोग्रामिंग अनुशासन और प्रयास की आवश्यकता होती है जो आवश्यक नहीं होना चाहिए।
Listing 1
और Listing 2
लिंक टूट गए हैं। एक नज़र देख लो।
एक और महत्वपूर्ण अंतर: typedef
एस आगे घोषित नहीं किया जा सकता है। तो typedef
विकल्प के लिए आपके पास #include
वह फ़ाइल होनी चाहिए typedef
, जिसका अर्थ यह है कि #include
आपके पास जो कुछ .h
भी है, उसमें वह फ़ाइल भी शामिल है, चाहे उसे सीधे इसकी आवश्यकता है या नहीं, और इसी तरह। यह निश्चित रूप से बड़ी परियोजनाओं पर आपके निर्माण समय को प्रभावित कर सकता है।
बिना typedef
, कुछ मामलों में आप केवल struct Foo;
अपनी .h
फ़ाइल के शीर्ष पर एक आगे की घोषणा को जोड़ सकते हैं , और आपकी फ़ाइल में केवल #include
संरचनात्मक परिभाषा .cpp
।
वहाँ है एक अंतर है, लेकिन सूक्ष्म। इसे इस तरह देखें: struct Foo
एक नए प्रकार का परिचय देता है। दूसरा एक अनाम struct
प्रकार के लिए फू (और नया प्रकार नहीं) नामक एक उपनाम बनाता है ।
.१.३ टाइप्डिफ निर्दिष्ट
1 [...]
टाइप्डिफ स्पेसिफायर के साथ घोषित एक नाम टाइपडेफ-नाम बन जाता है। इसकी घोषणा के दायरे में, एक टाइपराइफ-नाम वाक्य-विन्यास के अनुसार एक कीवर्ड के समान होता है और क्लॉज़ 8. में वर्णित तरीके से पहचानकर्ता के साथ जुड़े प्रकार को टाइप करता है। एक टाइप-बीफ़-नाम इस प्रकार दूसरे प्रकार का एक पर्याय है। एक टाइप-बीफ़-नाम एक नए प्रकार का परिचय नहीं देता है जिस तरह एक वर्ग घोषणा (9.1) या एनम घोषणा करता है।
8 यदि टाइप किए गए घोषणा में अनाम वर्ग (या एनम) को परिभाषित किया जाता है, तो घोषणा के द्वारा घोषित पहला टाइपडेफ-नाम उस वर्ग प्रकार (या एनम प्रकार) का उपयोग केवल लिंकेज उद्देश्यों के लिए वर्ग प्रकार (या एनम प्रकार) को दर्शाने के लिए किया जाता है ( 3.5)। [ उदाहरण:
typedef struct { } *ps, S; // S is the class name for linkage purposes
तो, एक टाइप्डेफ हमेशा एक प्लेसहोल्डर / एक अन्य प्रकार के पर्याय के रूप में उपयोग किया जाता है।
आप टाइपडिफ़ संरचना के साथ आगे की घोषणा का उपयोग नहीं कर सकते।
संरचना स्वयं एक अनाम प्रकार है, इसलिए आपके पास घोषणा करने के लिए वास्तविक नाम नहीं है।
typedef struct{
int one;
int two;
}myStruct;
इस अभ्यस्त काम की तरह एक आगे की घोषणा:
struct myStruct; //forward declaration fails
void blah(myStruct* pStruct);
//error C2371: 'myStruct' : redefinition; different basic types
myStruct
टैग नेमस्पेस में रहता है और टाइप नेड_फेड myStruct
सामान्य नामस्थान में रहता है जहां अन्य पहचानकर्ता जैसे फ़ंक्शन नाम, स्थानीय चर नाम रहते हैं। इसलिए कोई विरोधाभास नहीं होना चाहिए। यदि आपको संदेह है कि इसमें कोई त्रुटि है तो मैं आपको अपना कोड दिखा सकता हूं।
typedef
साथ केवल एक , आगे की घोषणा है typedef
, तो अनाम संरचना का संदर्भ नहीं है। इसके बजाय आगे की घोषणा टैग के साथ एक अधूरी संरचना की घोषणा करती है myStruct
। इसके अलावा, की परिभाषा को देखे बिना typedef
, typedef
ईडी नाम का उपयोग करने वाला फ़ंक्शन प्रोटोटाइप कानूनी नहीं है। इस प्रकार जब भी हमें myStruct
एक प्रकार को निरूपित करने के लिए उपयोग करने की आवश्यकता होती है, तो हमें पूरे टाइपफेड को शामिल करना होगा । अगर आपने मुझे गलत समझा तो मुझे ठीक करें। धन्यवाद।
C टाइप में 'टाइपकेफ स्ट्रक्चर' और 'स्ट्रक्चर' के बीच एक महत्वपूर्ण अंतर यह है कि 'टाइपडीफ स्ट्रक्चर' में इनलाइन मेंबर इनिशियलाइजेशन काम नहीं करेगा।
// the 'x' in this struct will NOT be initialised to zero
typedef struct { int x = 0; } Foo;
// the 'x' in this struct WILL be initialised to zero
struct Foo { int x = 0; };
x
में आरम्भिक है। कोलिरु ऑनलाइन आईडीई में परीक्षण देखें (मैंने इसे 42 से शुरू किया था इसलिए यह शून्य से अधिक स्पष्ट है कि असाइनमेंट में वास्तव में जगह है)।