2010-09-29 76 views
11

सी ++ और जावा में, डेटा संरचनाओं में private, public और protected क्षेत्र हो सकते हैं। मैं इस अवधारणा को एक सी भाषा प्रोग्राम में लिखना चाहता हूं जिसे मैं लिख रहा हूं।निजी और सार्वजनिक वर्गों में विभाजन संरचना?

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

नोट: भाषा दुकान द्वारा चुना गया है, इसलिए मैं अटक सी

धन्यवाद में ऑब्जेक्ट ओरिएंटेड अवधारणाओं को लागू करने कर रहा हूँ।

+0

सूचना छिपाने और encapsulation ओओडी भविष्यवाणी करता है। –

उत्तर

20

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

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

एक हेडर में, foo.h:

struct FooPrivate; 

    struct Foo { 
    /* public: */ 
     int x; 
     double y; 
    /* private: */ 
     struct FooPrivate* p; 
    }; 

    extern struct Foo* Foo_Create(); /* "constructor" */ 

    extern void Foo_DoWhatever(struct Foo* foo); /* "member function" */ 

कार्यान्वयन में, foo.c:

struct FooPrivate { 
    int z; 
    }; 

    struct Foo* Foo_Create() 
    { 
    struct Foo* foo = malloc(sizeof(Foo)); 

    foo->p = malloc(sizeof(FooPrivate)); 

    foo->x = 0; 
    foo->y = 0; 
    foo->p->z = 0; 

    return foo; 
    } 

    void Foo_DoWhatever(struct Foo* foo) 
    { 
     foo->p->z = 4; /* Can access "private" parts of foo */ 
    } 

एक कार्यक्रम में:

#include "foo.h" 

    int main() 
    { 
     struct Foo* foo = Foo_Create(); 

     foo->x = 100; /* Can access "public" parts of foo */ 
     foo->p->z = 20; /* Error! FooPrivate is not fully declared here! */ 

     Foo_DoWhatever(foo); /* Can call "member" function */ 

     return 0; 
    } 

नोट उदाहरण के लिए निजी डेटा के लिए स्मृति आवंटित करने के लिए "कन्स्ट्रक्टर" फ़ंक्शन का उपयोग करने की आवश्यकता है। जाहिर है, निजी डेटा को सही तरीके से डिलीकेट करने के लिए आपको इसे विशेष "विनाशक" फ़ंक्शन के साथ जोड़ना होगा।

या, वैकल्पिक रूप से, अगर आप कोई सार्वजनिक क्षेत्रों जो भी करने के लिए अपने struct चाहते हैं, तो आप पूरे struct अपारदर्शी बना सकता है, और सिर्फ हैडर वास्तविक परिभाषा के साथ की तरह

struct Foo; 

    extern struct Foo* Foo_Create(); /* "constructor" */ 

    extern void Foo_DoWhatever(struct Foo* foo); /* "member function" */ 

कुछ है हो foo.c में struct Foo का, और गेटटर और सेटर फ़ंक्शन किसी भी प्रॉपर्टी के लिए उपलब्ध हैं जो आप सीधे पहुंच प्रदान करना चाहते हैं।

+0

+1 मुझे मुर्गी मुहावरे के बारे में याद दिलाने के लिए धन्यवाद। मैंने इसे सी भाषा में लागू करने पर कभी विचार नहीं किया। –

+2

सी 99 में, आप पॉइंटर को 'स्ट्रक्चर फूप्रिवाइट' में लचीली सरणी सदस्य 'स्ट्रक्चर फूप्रिवाट पी []' के साथ बदलना चाहेंगे। यह इंटरफ़ेस के उपयोगकर्ता को 'स्ट्रक्चर फू' की गड़बड़ी-प्रतिलिपि बनाने से रोक देगा, क्योंकि यह 'स्ट्रक्चर फू' को अधूरा प्रकार बना देगा। – caf

+0

@caf क्या आप विस्तारित कर सकते हैं इसके बदले लचीले सरणी सदस्यों का उपयोग करने के लिए उत्तर की आवश्यकता होगी? – CMCDragonkai

0

मुझे आपके लिए खेद है, क्योंकि सी में विभिन्न ओओ अवधारणाओं को मैश करना अक्सर गोल छेद में स्क्वायर पेग की तरह होता है। कहा जा रहा है कि, GObject में सार्वजनिक और निजी सदस्यों के लिए समर्थन है, लेकिन यह पृथ्वी पर मेरे सबसे कम पसंदीदा आर्किटेक्चर में से एक है। यदि आप मामूली प्रदर्शन हिट से चिंतित नहीं हैं, तो आप एक सरल समाधान करने में सक्षम हो सकते हैं - एक माध्यमिक संरचना है जो निजी सदस्यों से भरी हुई है, और प्राथमिक (सार्वजनिक) संरचना से उस संरचना में अज्ञात सूचक है।

+1

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

+0

(ए) गोब्जेक्ट एक ओपन-सोर्स लाइब्रेरी है, हालांकि स्वीकार्य रूप से यहां तक ​​कि लाइसेंस समस्याएं भी हो सकती हैं; (बी) माध्यमिक निजी संरचना पुस्तकालय की आवश्यकता नहीं है। – Reinderien

9

अवधारणा कभी कभी सी में प्रयोग किया जाता

// lib.h 
typedef struct { 
    int publicInt; 
    //... 
    char * publicStr; 
} Public; 

Public * getPublic(); 
int function(Public * public); 

// lib.c 

typedef struct { 
    Public public; 
    int privateInt; 
    // ... 
    char * privateStr 
} Private; 

static Private * getPrivate(); 

Public * getPublic() { return (Public*) getPrivate(); } 
int function(Public * public) { 
    Private * private = (Private *) public; 
    // ... 
} 

यह मानक चाल है कि एक struct के लिए सूचक एक struct में पहला तत्व के लिए सूचक के साथ अदला-बदली जा सकती है, का उपयोग करता है।

आप सभी अपने क्षेत्रों को निजी रखना चाहते हैं, तो यह और भी आसान है:

// lib2.h 
typedef struct AllPrivate * Handle; 
Handle getHandle(); 
int function2(Handle handle); 

// lib2.c 
struct AllPrivate { /* ... */ } 

फ़ाइलें कि #include lib2.h, शिकायत नहीं होगा, क्योंकि हम केवल struct AllPrivate * उपयोग करते हैं, और सभी संकेत ही कर रहे हैं आकार, इसलिए संकलक को struct AllPrivate के अंदरूनी हिस्से को जानने की आवश्यकता नहीं है।

एक संरक्षित क्षेत्र ऐसा करने के लिए, आप बस तो यह सुनिश्चित करें कि dev/include आसपास पारित नहीं किया जाता है बनाने का मामला है

// include/public.h 
struct Public { /* ... */ } 
struct Public * getPublic(); 
int somePublicFunction(struct Public *); 

// dev/include/protected.h 
struct Protected { struct Public public; /* ... */ } 
struct Protected * getProtected(); 
int someProtectedFunction(struct Protected *); 

// dev/src/private.c 
struct Private { struct Protected protected; /* ... * /} 
struct Public * getPublic() { return (struct Public *) getPrivate(); } 
struct Public * getProtected() { return (struct Protected *) getPrivate(); } 
int somePublicFunction(struct Public * public) { 
    struct Private private = (struct Private *) public; 
    // ... 
} 
int someProtectedFunction(struct Protected * protected) { 
    struct Private private = (struct Private *) protected; 
    // ... 
} 

परिभाषित करने के लिए होगा।

2

डेटा फ़ील्ड के लिए - बस उनका उपयोग न करें। आप कुछ चाल कर सकते हैं जैसे उन्हें अपने उपयोग को हतोत्साहित करने के लिए पागल नाम देना, लेकिन इससे लोगों को नहीं रोका जा सकता है। ऐसा करने का एकमात्र असली तरीका एक और निजी संरचना बनाना है जिसे आपके लाइब्रेरी फ़ंक्शंस द्वारा शून्य सूचक द्वारा एक्सेस किया जाता है।

निजी कार्यों के लिए - फ़ाइल static फ़ंक्शंस का उपयोग करें। अपने सभी पुस्तकालय कार्यों को एक सी फ़ाइल में रखें और उन लोगों को घोषित करें जिन्हें आप static के रूप में निजी बनाना चाहते हैं और उन्हें किसी भी शीर्षलेख फ़ाइलों में न रखें।

1

अक्सर सम्मेलन द्वारा, एक निजी सदस्य के नाम पर अतिरिक्त अंडरस्कोर होता है, या _pri जैसे कुछ जोड़ा जाता है। या संभवतः एक टिप्पणी। यह तकनीक यह सुनिश्चित करने के लिए कंपाइलर-लागू जांच नहीं करती है कि कोई भी उन क्षेत्रों को अनुपयुक्त रूप से एक्सेस नहीं करता है, लेकिन struct को पढ़ने वाले किसी को भी चेतावनी के रूप में कार्य करता है कि सामग्री कार्यान्वयन के विवरण हैं और उन्हें उन पर नज़र डालना या पोक नहीं करना चाहिए।

एक और आम तकनीक आपकी संरचना को अपूर्ण प्रकार के रूप में बेनकाब करना है। उदाहरण के लिए, अपने हेडर फाइल में, आप हो सकता है:

struct my_struct; 

void some_function(struct my_struct *); 

और कार्यान्वयन में, या कुछ आंतरिक हेडर जो पुस्तकालय के उपभोक्ताओं के लिए सुलभ नहीं है, तुम हो:

struct my_struct 
{ 
    /* Members of that struct */ 
}; 

आप कर सकते हैं शून्य पॉइंटर्स के साथ समान चाल भी करें, जो कोड के "निजी" हिस्से में सही स्थान पर आते हैं। यह दृष्टिकोण कुछ लचीलापन खो देता है (उदाहरण के लिए, आपके पास एक अनिर्धारित प्रकार का स्टैक-आवंटित उदाहरण नहीं हो सकता है), लेकिन यह स्वीकार्य हो सकता है।

यदि आप निजी और सार्वजनिक सदस्यों का मिश्रण करना चाहते हैं, तो आप उपरोक्त की तरह ही काम कर सकते हैं, लेकिन निजी संरचना सूचक को सार्वजनिक के सदस्य के रूप में स्टोर कर सकते हैं, और इसे लाइब्रेरी के सार्वजनिक उपभोक्ताओं में अधूरा छोड़ दें ।

हालांकि, यह कुछ संकेत प्रदान करता है, जो प्रदर्शन को नुकसान पहुंचा सकता है। वहाँ कुछ (आम तौर पर गैर-पोर्टेबल है, लेकिन उचित compilers पर काम करेंगे) कर रहे हैं टाइप-punning चालें आप भी उपयोग कर सकते हैं:

struct public_struct 
{ 
    int public_member; 
    int public_member2; 
    /* etc.. */ 
}; 

struct private_struct 
{ 
    struct public_struct base_members; 

    int private_member1; 
    int private_member2; 
}; 

void some_function(struct public_struct *obj) 
{ 
    /* Hack alert! */ 
    struct private_struct *private = (struct private_struct*)obj; 
} 

यह भी मान लिया है कि आप ढेर पर या स्थिर भंडारण में इन वस्तुओं की दुकान नहीं कर सकते हैं , या संकलन समय पर आकार प्राप्त करें।

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