सी

2009-02-11 1 views
23

में डिफ़ॉल्ट कन्स्ट्रक्टर क्या संरचना के साथ परिभाषित सी उपयोगकर्ता प्रकारों के लिए किसी प्रकार का डिफॉल्ट कन्स्ट्रक्टर (सी ++ एक जैसा) है?सी

मेरे पास पहले से एक मैक्रो है जो एक तेज प्रारंभकर्ता (जैसे pthread_mutex के लिए) की तरह काम करता है, लेकिन मैं जानना चाहता था कि क्या आप किसी भी मौके पर घोषणा में भरे हुए ढांचे के कुछ (या सभी) फ़ील्ड हैं या नहीं।

उदाहरण के लिए, pthread_mutex उदाहरण के साथ, मैं

pthread_mutex_t my_mutex; 

,

pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER; 

उत्तर

32

आप प्रारंभकर्ता फ़ंक्शन बना सकते हैं जो संरचना में पॉइंटर लेते हैं। यह सामान्य अभ्यास था।

ऐसे कार्य भी जो एक संरचना बनाते हैं और इसे प्रारंभ करते हैं (एक कारखाने की तरह) - इसलिए ऐसा कोई समय नहीं है जहां संरचना "क्लाइंट" कोड में "अनियमित" हो। बेशक - मान लिया गया है कि लोगों को सम्मेलन का पालन करें और "निर्माता"/कारखाने का उपयोग करें ...

कोई त्रुटि malloc या मुफ्त

somestruct* somestruct_factory(/* per haps some initializer agrs? */) 
{ 
    malloc some stuff 
    fill in some stuff 
    return pointer to malloced stuff 
} 


void somestruct_destructor(somestruct*) 
{ 
    do cleanup stuff and also free pointer 
    free(somestruct); 
} 

किसी ने शायद साथ आ और यह बताएं कि होगा की जाँच कर के साथ भयानक छद्म कोड कुछ शुरुआती सी ++ प्रीप्रोसेसरों/कंपाइलर्स ने सी

+3

ओह सीफ्रंट, हम आपको कैसे याद करते हैं। – joeforker

+5

... एक भयानक जलती हुई धड़कन की तरह। – Randolpho

+0

और सीफ्रंट ने शुरुआत में कन्स्ट्रक्टर को कैसे संभाला है? – claf

8

नहीं जैसा प्रभाव दिखाने के लिए सीधे नहीं करना चाहते हैं। निकटतम आप ऐसा कर सकते हैं जो एक ऐसा फ़ंक्शन लिखना है जो किसी उदाहरण को आवंटित करता है और कुछ फ़ील्ड को पॉप्युलेट करता है। आपको आश्चर्य आप "सामान्य" सी खैर में सदस्य कार्य कर सकते हैं कि अगर

struct file create_file(int i, float f) { 
    struct file obj = { i, f }; 
    // other code here... 
    return obj; 
} 

, आप कुछ हद तक कर सकते हैं:

4

आप एक समारोह है कि सी struct रिटर्न लिख सकते हैं। मैं वस्तु-जैसा-प्रथम-तर्क शैली पसंद करता हूं। आप पहली बार तर्क के रूप में अपनी संरचना में एक सूचक को पास करते हैं। इस तरह, आप कई कार्य हो सकता है, अपने वस्तुओं के लिए इंटरफेस को परिभाषित:

int file_get_integer(struct file *self) { return self->i; } 
float file_get_float(struct file *self) { return self->f; } 

आपको लगता है कि शैली में लिखते हैं, क्या आप अंत में है एक सार डेटा प्रकार है। मैं सदस्य समारोह कॉल उनके struct में समारोह संकेत होने और उसके बाद कार्य करके C++ में इस्तेमाल किया वाक्य रचना की नकल लोगों को देखा है:

obj.get_integer(&obj); 

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

+0

उम्मीद है कि आपका कंपाइलर रिटर्न स्टेटमेंट में पूरी संरचना की प्रतिलिपि से बचने के लिए पर्याप्त स्मार्ट है। – joeforker

+2

जैसा कि जोफॉर्कर अप्रत्यक्ष रूप से इंगित करता है, कंबल रिटर्न स्टेटमेंट की तुलना में पॉइंटर का उपयोग करना बेहतर होता है। क्या होगा यदि आपकी संरचना विशेष रूप से बड़ी है? अधिकांश कंपाइलर रिटर्न वैल्यू कॉपी करेंगे। – Randolpho

+0

यदि यह बहुत बड़ा है तो मैं इसे पॉइंटर ले जाऊंगा। लेकिन इस मामले में (और संभवतः लगभग सभी अन्य मामलों) यह काफी छोटा है। मैं ढेर पर बड़ी मात्रा में डेटा डालूंगा और वैसे भी एक सूचक को संरचना में डाल दूंगा। –

0

नहीं, कोई भी डेटा डेटा का एक गुच्छा नहीं है। आप structs के भीतर कार्यों की घोषणा नहीं कर सकते हैं, इसलिए इसके लिए एक निर्माता बनाने का कोई तरीका नहीं है।

+0

आप सी में structs, या कम से कम फ़ंक्शन पॉइंटर्स में फ़ंक्शन शामिल कर सकते हैं। आप उनमें रचनाकार रख सकते हैं, और उन्हें सम्मेलन द्वारा बुला सकते हैं। पिछली बार मैंने देखा कि कोई असली गड़बड़ था, और यह मेरे लिए लायक नहीं था, लेकिन आप इसे कर सकते हैं। –

+0

-2 कुछ ऐसा करने के लिए कठोर लगता है जो बिल्कुल सही है। न्याय के लिए +1। आप "कन्स्ट्रक्टर" नामक एक फ़ंक्शन पॉइंटर डाल सकते हैं, लेकिन आपको इसे कॉल करने से पहले एक वैश्विक फ़ंक्शन को इंगित करने के लिए अभी भी बताना होगा, ताकि आप वैश्विक फ़ंक्शन को सीधे कॉल कर सकें! इसके अलावा, आपको "यह" नहीं मिलेगा। – MrZebra

+0

मेरे द्वारा +1 भी .. जबकि फ़ंक्शन पॉइंटर्स के साथ रचनात्मक होना संभव है, ऐसा करने के लिए बहुत कम कारण है। –

1

वास्तव में नहीं। अगर मुझे सही याद है, तो कक्षाओं में सबसे नज़दीक आपको संरचनाएं मिलती हैं। आप स्मृति आवंटित करते हैं और खेतों को पॉप्युलेट करते हैं। मैं नहीं देखता कि आप इसके लिए एक सामान्य कन्स्ट्रक्टर प्रकार कैसे बनायेंगे। सैद्धांतिक रूप से, आप एक मैक्रो लिख सकते हैं जो इनमें से कुछ करेगा। यकीन नहीं है कि यह वास्तव में सार्थक है हालांकि।

+0

क्या आप अपना मैक्रो विचार विकसित कर सकते हैं? – claf

+0

कारखाने के कार्यों के बारे में कभी सुना है? एक सरल कार्य जो संरचना आवंटित करता है और पॉप्युलेट करता है। मैक्रोज़ की कोई ज़रूरत नहीं है। वास्तव में, यह वास्तव में सी ++ रचनाकार क्या करते हैं। – Javier

+0

@ जेवियर: हाँ, लेकिन केवल जावा संदर्भ में। मैंने 1 99 4 से सी का उपयोग नहीं किया है और वापस जाने की कोई इच्छा नहीं है :) – paul

2

यह मानते हुए कि आप, सी में ऐसा करना चाहते हैं तो अपने प्रश्न सी ++ में structs के बारे में नहीं है:

क्या मैं आमतौर पर करते हैं कि मैं सिर्फ इतना है कि struct करने के लिए एक सूचक लेता है एक समारोह बनाने के लिए, init_whatever, है (या अन्य चर), और इसे मेरे इच्छित मानों पर सेट करता है।

यदि यह एक वैश्विक चर (जो शून्य करने के लिए आरंभ नहीं हो जाता) आप इन सबसे छुटकारा पाना में एक "प्रारंभ" झंडा होने से एक तर्क-कम निर्माता अनुकरण कर सकता है, और फिर अपने अन्य कार्यों कि झंडा जाँच करें है, और ध्वज शून्य होने पर संरचना शुरू करें। मुझे पूरा यकीन नहीं है कि यह एक अच्छा विचार है, यद्यपि।

और, जैसा कि किसी और का उल्लेख किया, तुम भी कुछ मैक्रो के साथ भयानक कर सकता है ...

3

असल में, सी ++ संकेत दिए गए जो तरीकों के पते की सूची बनाता है। इस सूची को कक्षा परिभाषा कहा जाता है (कक्षा डीफ़ में कुछ और डेटा है, लेकिन हम अभी इसके लिए अनदेखा करते हैं)।

एक आम पैटर्न शुद्ध सी में "वर्ग" के लिए एक "struct वर्ग" को परिभाषित करने के लिए है। संरचना के क्षेत्र में से एक कारखाना समारोह है जो कक्षा के "उदाहरण" देता है।

typedef struct __class * class; 
typedef void (*ctor_ptr)(class); 
struct class { 
    char * name; 
    ctor_ptr ctor; 
    ... destructor and other stuff ... 
} 

#define NEW(clz) ((struct something *)(((struct class *)clz)->ctor(clz))) 

अब, आप प्रत्येक वर्ग आप के लिए प्रकार "struct वर्ग" के ढांचे बनाने के द्वारा कक्षाएं आप परिभाषित कर सकते हैं और फिर उन्हें में संग्रहीत निर्माता कहते हैं: मैं डाले छिपाने के लिए मैक्रो का उपयोग करने के लिए सुझाव देते हैं। एक ही है, नाशक के लिए चला जाता है आदि

आप अपने उदाहरणों के लिए तरीके चाहते हैं, उन्हें वर्ग संरचना में डाल दिया और उदाहरण struct में वर्ग के लिए एक सूचक रखना चाहिए:

#define NEW_SOMETHING() ((struct something *)NEW(&something_definition)) 
#define METHOD(inst, arg) ((struct something_class *)(((struct something *)inst)->clz)->method(inst, arg)) 

NEW_SOMETHING पैदा करेगा संरचना something_definition में संग्रहीत कक्षा परिभाषा का उपयोग करके "कुछ" का एक नया उदाहरण। METHOD इस उदाहरण पर एक "विधि" का आह्वान करेगा। ध्यान दें कि वास्तविक कोड के लिए, आप यह जांचना चाहेंगे कि inst वास्तव में something का एक उदाहरण है (क्लास पॉइंटर्स की तुलना करें, ऐसा कुछ)।

विरासत प्राप्त करने के लिए पाठक के लिए एक अभ्यास के रूप में थोड़ा मुश्किल और छोड़ दिया गया है।

ध्यान दें कि आप जादुई कुछ और के साथ अपने CPU को प्रतिस्थापित नहीं करता सब कुछ आप शुद्ध सी ए सी ++ संकलक में सी में कर सकते हैं ++ कर सकते हैं। यह करने के लिए यह बहुत अधिक कोड लेता है।

आपको एक उदाहरण को देखने के लिए, glib (जीटीके + परियोजना का हिस्सा) की जाँच करें।

+0

कभी गोबजेक्ट के बारे में सुना ? – joeforker

+0

@ जो: कभी अमिगा के बारे में सुना? :) –

+0

मेरी गलती, मेरा प्रश्न डिफ़ॉल्ट कन्स्ट्रक्टर के बारे में था, मैं एक कन्स्ट्रक्टर को कॉल किए बिना घोषणा में शुरू की गई संरचना का कुछ क्षेत्र रखना चाहता हूं। – claf

16

सी ++ इस मामले में सी से अलग है इस संबंध में कि इसमें कोई "वर्ग" नहीं है। हालांकि, सी (कई अन्य भाषाओं) अभी भी ऑब्जेक्ट उन्मुख प्रोग्रामिंग के लिए उपयोग किया जा सकता है। इस मामले में, आपका कन्स्ट्रक्टर एक ऐसा कार्य हो सकता है जो एक संरचना शुरू करता है। यह रचनाकारों के समान है (केवल एक अलग वाक्यविन्यास)। एक और अंतर यह है कि आपको malloc() (या कुछ संस्करण) का उपयोग करके ऑब्जेक्ट आवंटित करना होगा। सी ++ में आप 'नया' ऑपरेटर का उपयोग करेंगे।

उदा।सी ++ कोड:

class A { 
    public: 
    A() { a = 0; } 
    int a; 
}; 

int main() 
{ 
    A b; 
    A *c = new A; 
    return 0; 
} 

बराबर सी कोड: एक निर्माता के रूप में सी में होगा ++

struct A { 
    int a; 
}; 

void init_A_types(struct A* t) 
{ 
    t->a = 0; 
} 

int main() 
{ 
    struct A b; 
    struct A *c = malloc(sizeof(struct A)); 
    init_A_types(&b); 
    init_A_types(c); 
    return 0; 
} 

समारोह 'init_A_types' काम करता है।

1

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

यदि यह आपके लिए काम नहीं करता है तो GObject पर एक नज़र डालें। http://en.wikipedia.org/wiki/GObject। (

GLib वस्तु प्रणाली, या GObject, एक मुक्त सॉफ्टवेयर पुस्तकालय है कवर: यह एक वस्तु जीटीके और Gnome में प्रयोग किया जाता सी के लिए प्रणाली है कि काफी क्रैंक 'सी में वस्तुओं "11.

के लिए विकिपीडिया से है एलजीपीएल द्वारा) जो एक पोर्टेबल ऑब्जेक्ट सिस्टम और पारदर्शी क्रॉस-भाषा इंटरऑपरेबिलिटी प्रदान करता है।

सिस्टम रचनाकारों, विनाशकों, एकल विरासत, इंटरफेस, वर्चुअल सार्वजनिक और निजी विधियों और आगे का समर्थन करता है। यह सी ++ में एक ही चीजों को करने से भी ज्यादा कठिन और मुश्किल है। मज़े करो!

10

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

structs के साथ समस्या यह है कि सब कुछ सार्वजनिक है इसलिए कोई डेटा छुपा नहीं है।

हम इसे ठीक कर सकते हैं।

आप दो शीर्षलेख फ़ाइलें बनाते हैं। एक "सार्वजनिक" हेडर फ़ाइल है जो आपके कोड के क्लाइंट द्वारा उपयोग की जाती है। यह इस तरह परिभाषाओं में शामिल हैं:

typedef void (*fDisposeFunction)(void *memoryBlock); 

typedef struct { 
    fDisposeFunction _dispose; 
} t_DisposableStruct; 

typedef struct { 
    t_DisposableStruct_disposer; /* must be first */ 
    PID _pid; 
    /* etc */ 
} t_ProcessStruct; 

typedef struct { 
    t_DisposableStruct_disposer; /* must be first */ 
    PERM_FLAGS _flags; 
    /* etc */ 
} t_PermissionsStruct; 

और फिर अपने कार्यान्वयन में आप कुछ इस तरह कर सकते हैं::

static void DisposeMallocBlock(void *process) { if (process) free(process); } 

static void *NewMallocedDisposer(size_t size) 
{ 
    assert(size > sizeof(t_DisposableStruct); 
    t_DisposableStruct *disp = (t_DisposableStruct *)malloc(size); 
    if (disp) { 
     disp->_dispose = DisposeMallocBlock; 
    } 
    return disp; 
} 

static void DisposeUsingDisposer(t_DisposableStruct *ds) 
{ 
    assert(ds); 
    ds->_dispose(ds); 
} 

t_ProcessHandle NewProcess() 
{ 
    t_ProcessHandle proc = (t_ProcessHandle)NewMallocedDisposer(sizeof(t_ProcessStruct)); 
    if (proc) { 
     proc->PID = NextPID(); /* etc */ 
    } 
    return proc; 
} 

void DisposeProcess(t_ProcessHandle proc) 
{ 
    DisposeUsingDisposer(&(proc->_disposer)); 
} 

typedef struct t_ProcessStruct *t_ProcessHandle; 

extern t_ProcessHandle NewProcess(); 
extern void DisposeProcess(t_ProcessHandle handle); 

typedef struct t_PermissionsStruct *t_PermissionsHandle; 

extern t_PermissionsHandle NewPermissions(); 
extern void DisposePermissions(t_PermissionsHandle handle); 

extern void SetProcessPermissions(t_ProcessHandle proc, t_PermissionsHandle perm); 

तो आप है कि इस तरह निर्धारणों वाली एक निजी हेडर फाइल बनाने

क्या होता है कि आप अपने सार्वजनिक हेडर फ़ाइलों में अपने structs के लिए घोषणाएं करते हैं। अब आपके structs अपारदर्शी हैं, जिसका मतलब है कि ग्राहक उनके साथ डिक नहीं कर सकते हैं। फिर, पूर्ण घोषणा में, आप प्रत्येक संरचना की शुरुआत में एक विनाशक शामिल करते हैं जिसे आप सामान्य रूप से कॉल कर सकते हैं। आप उसी मॉलोक आवंटक का उपयोग उसी व्यक्ति के लिए एक ही निपटान समारोह के लिए कर सकते हैं। आप उन तत्वों के लिए सार्वजनिक सेट/कार्य प्राप्त करते हैं जिन्हें आप उजागर करना चाहते हैं।

अचानक, आपका कोड बहुत अधिक सचेत है। आप केवल आवंटकों या फ़ंक्शन से structs प्राप्त कर सकते हैं जो आवंटकों को कॉल करते हैं, जिसका अर्थ है कि आप प्रारंभिकता को बाधित कर सकते हैं। आप विनाशकों में निर्माण करते हैं ताकि वस्तु को नष्ट किया जा सके। और तुम जाओ वैसे, t_DisposableStruct से बेहतर नाम t_vTableStruct हो सकता है, क्योंकि यह वही है। अब आप वर्चुअल विरासत बना सकते हैं जिसमें vTableStruct है जो सभी फ़ंक्शन पॉइंटर्स हैं। आप उन चीजों को भी कर सकते हैं जिन्हें आप शुद्ध ओओ भाषा (आमतौर पर) में नहीं कर सकते हैं, जैसे फ्लाई पर vtable के चुनिंदा तत्वों को बदलना।

महत्वपूर्ण बात यह है कि structs को सुरक्षित और प्रारंभिक बनाने के लिए एक इंजीनियरिंग पैटर्न है।

#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

#define new(TYPE, ...) memdup(&(TYPE){ __VA_ARGS__ }, sizeof(TYPE)) 

void * memdup(const void * obj, size_t size) 
{ 
    void * copy = malloc(size); 
    return copy ? memcpy(copy, obj, size) : NULL; 
} 

struct point 
{ 
    int x; 
    int y; 
}; 

int main() 
{ 
    int * i = new(int, 1); 
    struct point * p = new(struct point, 2, 3); 

    printf("%i %i %i", *i, p->x, p->y); 

    return 0; 
} 
+0

यह विडंबना है कि सी ++ के "फायदे" में से एक संरक्षित/निजी विनिर्देशकों के माध्यम से डेटा encapsulation प्रदान करना है, और फिर भी इसके अधिकांश उपयोग पैटर्न कक्षाओं को हर किसी के लिए अपनी हिम्मत दिखा रहा है (लेकिन अनुमति नहीं निश्चित रूप से उन्हें छूने के लिए कोई भी)। कोई सी में समान दृष्टिकोण ले सकता है, लेकिन यह अक्सर निराश नहीं होने के कारण होता है क्योंकि यह "ओओपी नहीं" होता है, या पिंपल दृष्टिकोण लेता है, जो मेरे अनुभव में केवल ओवरहेड और बॉयलरप्लेट कोड पेश करता है। – Tomis

2

यहाँ चारों ओर malloc(), memcpy() और C99 यौगिक शाब्दिक एक छोटे से मैक्रो जादू है। लेकिन एक टिप्पणी में आपने बताया कि आप एक "डिफ़ॉल्ट कन्स्ट्रक्टर" चाहते हैं - मुझे लगता है कि आप का मतलब है कि आप संरचना फ़ील्ड के कुछ (सभी?) को डिफ़ॉल्ट मानों में प्रारंभ करना चाहते हैं।

यह कुछ कोडिंग सम्मेलन का उपयोग करके सी में किया जाता है - या तो कार्य, मैक्रोज़, या मिश्रण। मैं आमतौर पर वह ऐसा कुछ करना -

struct some_struct { 
    int a; 
    float b; 
}; 
#define some_struct_DEFAULT { 0, 0.0f} 
struct some_struct *some_struct_create(void) { 
    struct some_struct *ptr = malloc(sizeof some_struct); 
    if(!ptr) 
     return ptr; 

    *ptr = some_struct_DEFAULT; 
    return ptr; 
} 
// (...) 
struct some_struct on_stack = some_struct_DEFAULT; 
struct some_struct *on_heap = some_struct_create(); 
2

कार्यों का उपयोग बना सकते हैं और संरचनाओं के निपटान के पहले ही उल्लेख किया गया है:

1

fallowing साधारण प्रोग्राम है कि एक निर्माता का उपयोग करता है। फ़ंक्शन "default_constructor" को किसी भी स्पष्ट फ़ंक्शन कॉल के बिना मुख्य अंदर बुलाया जाता है।

#include  <stdio.h> 

void __attribute__ ((constructor)) default_constructor() 
{ 
    printf("%s\n", __FUNCTION__); 
} 

int main() 
{ 
    printf("%s\n",__FUNCTION__); 
    return 0; 
} 

आउटपुट: default_constructor मुख्य

निर्माता समारोह के भीतर आप निर्माता समारोह में कुछ आरंभीकरण बयान शामिल कर सकते हैं और अंत में नाशक के रूप में परती में मुक्त कर सकते हैं,

#include <stdio.h> 
#include <stdlib.h> 

struct somestruct 
{ 
    int  empid; 
    char * name; 
}; 

struct somestruct * str1; 

void __attribute__ ((constructor)) a_constructor() 
{ 
    str1 = (struct somestruct *) malloc (sizeof(struct somestruct)); 
    str1 -> empid = 30228; 
    str1 -> name = "Nandan"; 
} 

void __attribute__ ((destructor)) a_destructor() 
{ 
    free(str1); 
} 

int main() 
{ 
    printf("ID = %d\nName = %s\n", str1 -> empid, str1 -> name); 
    return 0; 
} 

आशा यह आपकी मदद करेगा।