c++ - सी++ में 'स्ट्रक्चर' और 'टाइपपीफ स्ट्रक्चर' के बीच अंतर?




struct typedef (6)

'टाइपपीफ स्ट्रक्चर' और सी ++ में 'स्ट्रक्चर' के बीच एक महत्वपूर्ण अंतर यह है कि 'टाइपपीफ structs' में इनलाइन सदस्य प्रारंभिक कार्य नहीं करेगा।

// 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; };

सी ++ में, क्या कोई अंतर है:

struct Foo { ... };

तथा

typedef struct { ... } Foo;

आप टाइपपीफ स्ट्रक्चर के साथ आगे की घोषणा का उपयोग नहीं कर सकते हैं।

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

typedef struct{
    int one;
    int two;
}myStruct;

इस तरह की एक आगे की घोषणा काम नहीं करेगा:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types

एक और महत्वपूर्ण अंतर: typedef को आगे घोषित नहीं किया जा सकता है। तो typedef विकल्प के लिए आपको #include typedef युक्त फ़ाइल को #include करना होगा, जिसका अर्थ है कि #include आपके सब कुछ #include .h इसमें फ़ाइल भी शामिल है चाहे उसे सीधे इसकी आवश्यकता हो या नहीं, और इसी तरह। यह बड़ी परियोजनाओं पर आपके निर्माण के समय को निश्चित रूप से प्रभावित कर सकता है।

typedef बिना, कुछ मामलों में आप केवल struct Foo; की अग्रेषित घोषणा जोड़ सकते हैं struct Foo; अपनी .h फ़ाइल के शीर्ष पर, और केवल #include .cpp फ़ाइल में संरचना परिभाषा को शामिल करें।


संरचना डेटा प्रकार बनाना है। टाइपपीफ डेटा प्रकार के लिए उपनाम सेट करना है।


सी ++ में, केवल एक सूक्ष्म अंतर होता है। यह सी से एक होल्डओवर है, जिसमें यह एक फर्क पड़ता है।

सी भाषा मानक ( सी 8 9 §3.1.2.3 , सी 99 §6.2.3 , और सी 11 §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 प्रकार की वस्तुओं को स्वतंत्र रूप से घोषित कर सकते हैं।

निर्माण:

typedef struct Foo { ... } Foo;

घोषणा और typedef लिए सिर्फ संक्षेप है।

आखिरकार,

typedef struct { ... } Foo;

एक अनाम संरचना घोषित करता है और इसके लिए एक typedef बनाता है। इस प्रकार, इस निर्माण के साथ, टैग नामस्थान में इसका नाम नहीं है, केवल टाइपिफ़ नामस्थान में एक नाम है। इसका मतलब है कि इसे आगे घोषित नहीं किया जा सकता है। यदि आप आगे की घोषणा करना चाहते हैं, तो आपको इसे टैग नेमस्पेस में एक नाम देना होगा

सी ++ में, सभी struct / union / enum / class घोषणाएं कार्य करती हैं जैसे कि वे पूरी तरह से typedef 'ed हैं, जब तक कि नाम एक ही नाम के साथ किसी अन्य घोषणा द्वारा छिपाया न जाए। पूर्ण विवरण के लिए माइकल बोर का जवाब देखें।


इस डीडीजे लेख में , डैन सैक्स एक छोटे से क्षेत्र को बताते हैं जहां आप अपने structs (और कक्षाएं) टाइप नहीं करते हैं, तो बग रेंग सकते हैं:

यदि आप चाहते हैं, तो आप कल्पना कर सकते हैं कि सी ++ प्रत्येक टैग नाम के लिए टाइपिफ़ उत्पन्न करता है, जैसे कि

typedef class string string;

दुर्भाग्यवश, यह पूरी तरह सटीक नहीं है। काश यह इतना आसान था, लेकिन यह नहीं है। सी ++ सी के साथ असंगतताओं को शुरू किए बिना structs, यूनियनों या enums के लिए ऐसे typedefs उत्पन्न नहीं कर सकता है।

उदाहरण के लिए, मान लीजिए कि एक सी प्रोग्राम एक समारोह और नाम की संरचना दोनों की घोषणा करता है:

int status(); struct status;

फिर, यह बुरा अभ्यास हो सकता है, लेकिन यह सी है। इस कार्यक्रम में, स्थिति (स्वयं द्वारा) फ़ंक्शन को संदर्भित करती है; संरचना की स्थिति प्रकार को संदर्भित करती है।

यदि सी ++ ने स्वचालित रूप से टैग के लिए टाइपपीफ उत्पन्न किए हैं, तो जब आपने इस प्रोग्राम को सी ++ के रूप में संकलित किया है, तो संकलक उत्पन्न होगा:

typedef struct status status;

दुर्भाग्यवश, इस प्रकार का नाम फ़ंक्शन नाम से संघर्ष करेगा, और प्रोग्राम संकलित नहीं होगा। यही कारण है कि सी ++ प्रत्येक टैग के लिए बस टाइपिफ़ उत्पन्न नहीं कर सकता है।

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

इस प्रकार, एक सी प्रोग्राम जिसमें दोनों शामिल हैं:

int status(); struct status;

सी ++ के रूप में संकलित जब वही व्यवहार करता है। अकेले नाम की स्थिति फ़ंक्शन को संदर्भित करती है। कार्यक्रम केवल विस्तृत प्रकार के विनिर्देशक संरचना स्थिति का उपयोग कर प्रकार का उल्लेख कर सकता है।

तो यह कैसे बग कार्यक्रमों में रेंगने की अनुमति देता है? लिस्टिंग 1 में कार्यक्रम पर विचार करें। यह प्रोग्राम एक डिफ़ॉल्ट कन्स्ट्रक्टर के साथ एक वर्ग foo को परिभाषित करता है, और एक रूपांतरण ऑपरेटर जो foo ऑब्जेक्ट को char const * में परिवर्तित करता है। भाव

p = foo();

मुख्य में एक foo ऑब्जेक्ट बनाना चाहिए और रूपांतरण ऑपरेटर को लागू करना चाहिए। बाद के आउटपुट कथन

cout << p << '\n';

कक्षा foo प्रदर्शित करना चाहिए, लेकिन यह नहीं करता है। यह फ़ंक्शन foo प्रदर्शित करता है।

यह आश्चर्यजनक परिणाम होता है क्योंकि प्रोग्राम में शीर्षक 2 में दिखाया गया हैडर lib.h शामिल है। यह हेडर फ़ू नामक फ़ंक्शन को परिभाषित करता है। फ़ंक्शन नाम foo क्लास नाम foo को छुपाता है, इसलिए मुख्य रूप से foo का संदर्भ फ़ंक्शन को संदर्भित करता है, कक्षा नहीं। मुख्य रूप से एक विस्तृत प्रकार के विनिर्देशक का उपयोग कर कक्षा को संदर्भित कर सकते हैं, जैसा कि

p = class foo();

पूरे कार्यक्रम में इस तरह के भ्रम से बचने का तरीका क्लास नाम foo के लिए निम्नलिखित टाइपपीफ जोड़ना है:

typedef class foo foo;

कक्षा परिभाषा से पहले या बाद में तुरंत। यह टाइपपीफ प्रकार नाम foo और फ़ंक्शन नाम foo (लाइब्रेरी से) के बीच एक संघर्ष का कारण बनता है जो संकलन-समय त्रुटि को ट्रिगर करेगा।

मैं किसी ऐसे व्यक्ति के बारे में नहीं जानता जो वास्तव में इन टाइपिफ को लिखता है। इसके लिए बहुत सारे अनुशासन की आवश्यकता है। चूंकि लिस्टिंग 1 में से एक जैसी त्रुटियों की घटनाएं शायद बहुत छोटी हैं, आप कई इस समस्या से पहले कभी नहीं दौड़ते हैं। लेकिन अगर आपके सॉफ़्टवेयर में कोई त्रुटि शारीरिक चोट का कारण बन सकती है, तो आपको टाइपपीफ लिखना चाहिए इससे कोई फर्क नहीं पड़ता कि त्रुटि कितनी असंभव है।

मैं कल्पना नहीं कर सकता कि क्यों कोई भी कक्षा के समान दायरे में किसी फ़ंक्शन या ऑब्जेक्ट नाम के साथ कक्षा का नाम छिपाना चाहेगा। सी में छुपा नियम एक गलती थी, और उन्हें सी ++ में कक्षाओं तक विस्तारित नहीं किया जाना चाहिए था। दरअसल, आप गलती को सही कर सकते हैं, लेकिन इसके लिए अतिरिक्त प्रोग्रामिंग अनुशासन और प्रयास की आवश्यकता है जो आवश्यक नहीं होनी चाहिए।





typedef