C में ऑब्जेक्ट-ओरिएंटेड कोड लिखने के कुछ तरीके क्या हैं? खासकर बहुरूपता के संबंध में।
C में यह स्टैक ओवरफ्लो प्रश्न ऑब्जेक्ट-ओरिएंटेशन भी देखें ।
C में ऑब्जेक्ट-ओरिएंटेड कोड लिखने के कुछ तरीके क्या हैं? खासकर बहुरूपता के संबंध में।
C में यह स्टैक ओवरफ्लो प्रश्न ऑब्जेक्ट-ओरिएंटेशन भी देखें ।
जवाबों:
हाँ। वास्तव में एक्सल श्राइनर अपनी पुस्तक "ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग इन एएनएसआई-सी" मुफ्त में प्रदान करता है जो विषय को काफी अच्छी तरह से कवर करता है।
चूंकि आप बहुरूपता के बारे में बात कर रहे हैं तो हाँ, आप कर सकते हैं, हम उस तरह के सामान कर रहे थे जैसे सी ++ के बारे में आया था।
मूल रूप से आप struct
उस डेटा के लिए संबंधित फ़ंक्शन को इंगित करने के लिए डेटा और फ़ंक्शन पॉइंटर्स की एक सूची दोनों का उपयोग करते हैं।
इसलिए, संचार वर्ग में, आपके पास एक खुला, पढ़ना, लिखना और पास कॉल होगा जो संरचना में चार फ़ंक्शन बिंदुओं के रूप में बनाए रखा जाएगा, एक वस्तु के लिए डेटा के साथ, कुछ इस तरह से:
typedef struct {
int (*open)(void *self, char *fspec);
int (*close)(void *self);
int (*read)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
int (*write)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
// And data goes here.
} tCommClass;
tCommClass commRs232;
commRs232.open = &rs232Open;
: :
commRs232.write = &rs232Write;
tCommClass commTcp;
commTcp.open = &tcpOpen;
: :
commTcp.write = &tcpWrite;
बेशक, ऊपर दिए गए कोड सेगमेंट वास्तव में "कंस्ट्रक्टर" जैसे होंगे rs232Init()
।
जब आप उस वर्ग से 'विरासत' लेते हैं, तो आप केवल अपने कार्यों को इंगित करने के लिए संकेत बदलते हैं। हर कोई जो उन कार्यों को बुलाता है, वह फ़ंक्शन पॉइंटर के माध्यम से करता है, जो आपको आपकी बहुरूपता देता है:
int stat = (commTcp.open)(commTcp, "bigiron.box.com:5000");
एक मैनुअल vtable की तरह।
यहां तक कि वर्चुअल क्लास भी हो सकती है, जहां पर NULL -the बिहेवियर के पॉइंट सेट करके वर्चुअल क्लास C ++ से थोड़ी अलग होगी (कंपाइल टाइम में एरर के बजाय रन-टाइम पर कोर डंप)।
यहाँ नमूना कोड का एक टुकड़ा है जो इसे प्रदर्शित करता है। प्रथम शीर्ष-स्तरीय वर्ग संरचना:
#include <stdio.h>
// The top-level class.
typedef struct sCommClass {
int (*open)(struct sCommClass *self, char *fspec);
} tCommClass;
फिर हमारे पास TCP 'उपवर्ग' के लिए कार्य हैं:
// Function for the TCP 'class'.
static int tcpOpen (tCommClass *tcp, char *fspec) {
printf ("Opening TCP: %s\n", fspec);
return 0;
}
static int tcpInit (tCommClass *tcp) {
tcp->open = &tcpOpen;
return 0;
}
और HTTP एक:
// Function for the HTTP 'class'.
static int httpOpen (tCommClass *http, char *fspec) {
printf ("Opening HTTP: %s\n", fspec);
return 0;
}
static int httpInit (tCommClass *http) {
http->open = &httpOpen;
return 0;
}
और अंत में इसे कार्रवाई में दिखाने के लिए एक परीक्षण कार्यक्रम:
// Test program.
int main (void) {
int status;
tCommClass commTcp, commHttp;
// Same 'base' class but initialised to different sub-classes.
tcpInit (&commTcp);
httpInit (&commHttp);
// Called in exactly the same manner.
status = (commTcp.open)(&commTcp, "bigiron.box.com:5000");
status = (commHttp.open)(&commHttp, "http://www.microsoft.com");
return 0;
}
यह उत्पादन का उत्पादन करता है:
Opening TCP: bigiron.box.com:5000
Opening HTTP: http://www.microsoft.com
इसलिए आप देख सकते हैं कि उप-वर्ग के आधार पर विभिन्न कार्यों को बुलाया जा रहा है।
tCommClass
नाम बदल दिया जाएगा tCommVT
, और एक tCommClass
संरचना में केवल tCommVT vt
"एक और केवल" वर्चुअल-टेबल की ओर इशारा करते हुए डेटा फ़ील्ड और एक एकल फ़ील्ड होगा। प्रत्येक उदाहरण के साथ सभी बिंदुओं को ले जाने से अनावश्यक ओवरहेड जुड़ जाता है और आप C ++, IMHO की तुलना में जावास्क्रिप्ट में सामान कैसे करेंगे, इससे अधिक मिलता जुलता है।
नाम स्थान अक्सर कर के होते हैं:
stack_push(thing *)
के बजाय
stack::push(thing *)
C ++ वर्ग जैसी किसी चीज़ में C संरचना बनाने के लिए आप इसे चालू कर सकते हैं:
class stack {
public:
stack();
void push(thing *);
thing * pop();
static int this_is_here_as_an_example_only;
private:
...
};
में
struct stack {
struct stack_type * my_type;
// Put the stuff that you put after private: here
};
struct stack_type {
void (* construct)(struct stack * this); // This takes uninitialized memory
struct stack * (* operator_new)(); // This allocates a new struct, passes it to construct, and then returns it
void (*push)(struct stack * this, thing * t); // Pushing t onto this stack
thing * (*pop)(struct stack * this); // Pops the top thing off the stack and returns it
int this_is_here_as_an_example_only;
}Stack = {
.construct = stack_construct,
.operator_new = stack_operator_new,
.push = stack_push,
.pop = stack_pop
};
// All of these functions are assumed to be defined somewhere else
और करो:
struct stack * st = Stack.operator_new(); // Make a new stack
if (!st) {
// Do something about it
} else {
// You can use the stack
stack_push(st, thing0); // This is a non-virtual call
Stack.push(st, thing1); // This is like casting *st to a Stack (which it already is) and doing the push
st->my_type.push(st, thing2); // This is a virtual call
}
मैंने विध्वंसक या नष्ट नहीं किया, लेकिन यह उसी पैटर्न का अनुसरण करता है।
this_is_here_as_an_example_only एक स्थिर वर्ग चर की तरह है - एक प्रकार के सभी उदाहरणों के बीच साझा किया जाता है। सभी विधियाँ वास्तव में स्थिर हैं, सिवाय इसके कि कुछ इसे ले *
st->my_type->push(st, thing2);
के बजायst->my_type.push(st, thing2);
struct stack_type my_type;
इसके बजायstruct stack_type * my_type;
Class
संरचना के बारे में कैसे ? यह O ++ C को C ++ से अधिक गतिशील बनाता है । उस के बारे में कैसा है? वैसे, +1।
मेरा मानना है कि अपने आप में उपयोगी होने के अलावा, OOP को C में लागू करना OOP सीखने और इसके आंतरिक कामकाज को समझने का एक शानदार तरीका है । कई प्रोग्रामर्स के अनुभव से पता चला है कि कुशलतापूर्वक और आत्मविश्वास से एक तकनीक का उपयोग करने के लिए, एक प्रोग्रामर को समझना चाहिए कि अंतर्निहित अवधारणाओं को अंततः कैसे लागू किया जाता है। सी में कक्षाएं, वंशानुक्रम और बहुरूपता का अनुकरण करना बस यही सिखाता है।
मूल प्रश्न का उत्तर देने के लिए, यहाँ कुछ संसाधन दिए गए हैं जो सिखाते हैं कि C में OOP कैसे करें:
एंबेडेडगुरुस.कॉम ब्लॉग पोस्ट "ऑब्जेक्ट आधारित प्रोग्रामिंग इन सी" से पता चलता है कि पोर्टेबल सी में कक्षाएं और एकल विरासत को कैसे लागू किया जाए: http://embeddedgurus.com/state-space/2008/01/object-based-programming-in-c /
अनुप्रयोग नोट "" सी + "- ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग इन सी" प्रीप्रोसेसर मैक्रोज़ का उपयोग करके सी में कक्षाएं, एकल वंशानुक्रम और देर से बाध्यकारी (बहुरूपता) को लागू करने का तरीका दिखाता है: http://www.state-machine.com/resources-cplus_3। 0_manual.pdf , उदाहरण कोड http://www.state-machine.com/resources/cplus_3b.ip से उपलब्ध है ।
मैंने इसे पूरा होते देखा है। मैं इसकी सिफारिश नहीं करूंगा। सी ++ मूल रूप से इस तरह से एक प्रीप्रोसेसर के रूप में शुरू हुआ जिसने सी कोड को मध्यवर्ती चरण के रूप में उत्पादित किया।
अनिवार्य रूप से आप जो कर रहे हैं वह आपके सभी तरीकों के लिए प्रेषण तालिका बनाता है जहां आप अपने फ़ंक्शन संदर्भों को संग्रहीत करते हैं। एक वर्ग को प्राप्त करना इस प्रेषण तालिका की नकल करना और उन प्रविष्टियों की जगह लेना होगा जिन्हें आप ओवरराइड करना चाहते थे, मूल विधि को कॉल करने के लिए आपके नए "तरीकों" के साथ अगर यह आधार विधि को लागू करना चाहता है। आखिरकार, आप C ++ को फिर से लिखना चाहते हैं।
glib
C में ऑब्जेक्टिव तरीके से नहीं लिखा है?
यकीन है कि संभव है। यह GObject है , जो फ्रेमवर्क सभी GTK + और GNOME पर आधारित है, करता है।
C stdio FILE उप-पुस्तकालय एक अप्रत्यक्ष सी में अमूर्तता, एनकैप्सुलेशन और मॉड्यूलरिटी बनाने का एक उत्कृष्ट उदाहरण है।
विरासत और बहुरूपता - अक्सर OOP के लिए आवश्यक माना अन्य पहलुओं - जरूरी उत्पादकता लाभ वे वादा प्रदान नहीं करते हैं और उचित तर्क है किया गया वे वास्तव में बाधा विकास और समस्या डोमेन के बारे में सोच सकते हैं कि।
एक पशु और कुत्ते के साथ तुच्छ उदाहरण: आप दर्पण C ++ के व्यवहार्य तंत्र (मोटे तौर पर वैसे भी)। आप आवंटन और इंस्टेंटेशन (Animal_Alloc, Animal_New) को भी अलग करते हैं, इसलिए हम कई बार मॉलॉक () को कॉल नहीं करते हैं। हमें this
पॉइंटर को भी स्पष्ट रूप से पास करना होगा ।
यदि आप गैर-आभासी कार्य करने के लिए थे, तो यह सही है। आप उन्हें केवल व्यवहार्य और स्थिर कार्यों में शामिल नहीं करते हैं, एक this
पॉइंटर की आवश्यकता नहीं होती है । बहु विरासत में आम तौर पर अस्पष्टताओं को हल करने के लिए कई vtables की आवश्यकता होती है।
साथ ही, आपको अपवाद हैंडलिंग करने के लिए setjmp / longjmp का उपयोग करने में सक्षम होना चाहिए।
struct Animal_Vtable{
typedef void (*Walk_Fun)(struct Animal *a_This);
typedef struct Animal * (*Dtor_Fun)(struct Animal *a_This);
Walk_Fun Walk;
Dtor_Fun Dtor;
};
struct Animal{
Animal_Vtable vtable;
char *Name;
};
struct Dog{
Animal_Vtable vtable;
char *Name; // Mirror member variables for easy access
char *Type;
};
void Animal_Walk(struct Animal *a_This){
printf("Animal (%s) walking\n", a_This->Name);
}
struct Animal* Animal_Dtor(struct Animal *a_This){
printf("animal::dtor\n");
return a_This;
}
Animal *Animal_Alloc(){
return (Animal*)malloc(sizeof(Animal));
}
Animal *Animal_New(Animal *a_Animal){
a_Animal->vtable.Walk = Animal_Walk;
a_Animal->vtable.Dtor = Animal_Dtor;
a_Animal->Name = "Anonymous";
return a_Animal;
}
void Animal_Free(Animal *a_This){
a_This->vtable.Dtor(a_This);
free(a_This);
}
void Dog_Walk(struct Dog *a_This){
printf("Dog walking %s (%s)\n", a_This->Type, a_This->Name);
}
Dog* Dog_Dtor(struct Dog *a_This){
// Explicit call to parent destructor
Animal_Dtor((Animal*)a_This);
printf("dog::dtor\n");
return a_This;
}
Dog *Dog_Alloc(){
return (Dog*)malloc(sizeof(Dog));
}
Dog *Dog_New(Dog *a_Dog){
// Explict call to parent constructor
Animal_New((Animal*)a_Dog);
a_Dog->Type = "Dog type";
a_Dog->vtable.Walk = (Animal_Vtable::Walk_Fun) Dog_Walk;
a_Dog->vtable.Dtor = (Animal_Vtable::Dtor_Fun) Dog_Dtor;
return a_Dog;
}
int main(int argc, char **argv){
/*
Base class:
Animal *a_Animal = Animal_New(Animal_Alloc());
*/
Animal *a_Animal = (Animal*)Dog_New(Dog_Alloc());
a_Animal->vtable.Walk(a_Animal);
Animal_Free(a_Animal);
}
पुनश्च। यह C ++ कंपाइलर पर जांचा जाता है, लेकिन इसे C कंपाइलर पर काम करना आसान होना चाहिए।
typedef
struct
सी। में अंदर संभव नहीं है
की जाँच करें GObject । यह C में OO और एक कार्यान्वयन है जो आप देख रहे हैं। यदि आप वास्तव में OO चाहते हैं, तो C ++ या किसी अन्य OOP भाषा के साथ जाएं। यदि आप OO भाषाओं से निपटने के लिए उपयोग किए जाते हैं, तो GObject कई बार काम करना कठिन हो सकता है, लेकिन किसी भी चीज़ की तरह, आपको सम्मेलनों और प्रवाह की आदत होगी।
यह पढ़ना दिलचस्प रहा है। मैं खुद उसी सवाल को टटोल रहा हूं, और इसके बारे में सोचने के फायदे इस प्रकार हैं:
एक गैर-ओओपी भाषा में ओओपी अवधारणाओं को कैसे लागू किया जाए, यह कल्पना करने की कोशिश मुझे ओओपी भाषा की ताकत (मेरे मामले में, सी ++) को समझने में मदद करती है। यह मुझे एक बेहतर प्रकार के आवेदन के लिए C या C ++ का उपयोग करने के बारे में बेहतर निर्णय लेने में मदद करता है - जहां एक का लाभ दूसरे को नापता है।
इस पर जानकारी और राय के लिए वेब ब्राउजिंग में मुझे एक लेखक मिला जो एक एम्बेडेड प्रोसेसर के लिए कोड लिख रहा था और केवल एक सी कंपाइलर उपलब्ध था: http://www.eetimes.com/discussion/other/4024626/Object-Oriented -सी-बनाना-फाउंडेशन-कक्षा-भाग -1
उनके मामले में, सादे C में OOP अवधारणाओं का विश्लेषण और अनुकूलन एक वैध खोज थी। ऐसा प्रतीत होता है कि वह ओवरहेड हिट के कारण कुछ ओओपी अवधारणाओं का त्याग करने के लिए खुला था, जिसके परिणामस्वरूप सी में उन्हें लागू करने का प्रयास किया गया था।
मैंने जो सबक लिया है, हाँ यह कुछ हद तक किया जा सकता है, और हाँ, इसे आज़माने के कुछ अच्छे कारण हैं।
अंत में, मशीन स्टैक पॉइंटर बिट्स को घुमा रही है, जिससे प्रोग्राम काउंटर जंप के आसपास हो जाता है और मेमोरी एक्सेस ऑपरेशन की गणना करता है। दक्षता के दृष्टिकोण से, आपके कार्यक्रम द्वारा किए गए इन गणनाओं में से कम, बेहतर ... लेकिन कभी-कभी हमें इस कर का भुगतान करना पड़ता है इसलिए हम अपने कार्यक्रम को इस तरह से व्यवस्थित कर सकते हैं जो मानव त्रुटि के लिए कम से कम अतिसंवेदनशील बनाता है। ओओपी भाषा संकलक दोनों पहलुओं को अनुकूलित करने का प्रयास करता है। प्रोग्रामर को C जैसी भाषा में इन अवधारणाओं को लागू करने में अधिक सावधानी बरतनी होगी।
आपको ऐप्पल के दस्तावेज़ीकरण को एपीआई के कोर फाउंडेशन सेट के लिए देखना उपयोगी हो सकता है। यह एक शुद्ध सी एपीआई है, लेकिन कई प्रकार ऑब्जेक्टिव-सी ऑब्जेक्ट समकक्षों के लिए तैयार हैं।
ऑब्जेक्टिव-सी के डिजाइन को देखने में भी आपको यह मददगार लग सकता है। यह C ++ से थोड़ा अलग है कि ऑब्जेक्ट सिस्टम को C फ़ंक्शन के संदर्भ में परिभाषित किया गया है, उदाहरण के objc_msg_send
लिए किसी ऑब्जेक्ट पर एक विधि को कॉल करना। कंपाइलर उन फ़ंक्शन कॉल में स्क्वायर ब्रैकेट सिंटैक्स का अनुवाद करता है, इसलिए आपको इसे जानने की ज़रूरत नहीं है, लेकिन आपके प्रश्न पर विचार करने से आपको यह सीखना उपयोगी हो सकता है कि यह हुड के नीचे कैसे काम करता है।
कई तकनीकें हैं जिनका उपयोग किया जा सकता है। सबसे महत्वपूर्ण एक और अधिक है कि परियोजना को कैसे विभाजित किया जाए। हम अपने प्रोजेक्ट में एक .h फ़ाइल और ऑब्जेक्ट के कार्यान्वयन के लिए एक .c फ़ाइल में घोषित किया जाता है। महत्वपूर्ण हिस्सा यह है कि सभी मॉड्यूल जिसमें .h फ़ाइल शामिल हैं, केवल एक ऑब्जेक्ट को एक के रूप में देखते हैं void *
, और .c फ़ाइल एकमात्र ऐसा मॉड्यूल है जो संरचना के आंतरिक भाग को जानता है।
एक वर्ग के लिए कुछ इस तरह हम एक उदाहरण के रूप में FOO नाम:
.H फ़ाइल में
#ifndef FOO_H_
#define FOO_H_
...
typedef struct FOO_type FOO_type; /* That's all the rest of the program knows about FOO */
/* Declaration of accessors, functions */
FOO_type *FOO_new(void);
void FOO_free(FOO_type *this);
...
void FOO_dosomething(FOO_type *this, param ...):
char *FOO_getName(FOO_type *this, etc);
#endif
C कार्यान्वयन फ़ाइल कुछ इस तरह होगी।
#include <stdlib.h>
...
#include "FOO.h"
struct FOO_type {
whatever...
};
FOO_type *FOO_new(void)
{
FOO_type *this = calloc(1, sizeof (FOO_type));
...
FOO_dosomething(this, );
return this;
}
इसलिए मैं उस मॉड्यूल के प्रत्येक फ़ंक्शन के लिए स्पष्ट रूप से एक ऑब्जेक्ट को पॉइंटर देता हूं। एक C ++ कंपाइलर इसे स्पष्ट रूप से करता है, और C में हम इसे स्पष्ट रूप से लिखते हैं।
मैं वास्तव this
में अपने कार्यक्रमों में उपयोग करता हूं, यह सुनिश्चित करने के लिए कि मेरा कार्यक्रम C ++ में संकलित नहीं करता है, और मेरे सिंटैक्स हाइलाइटिंग संपादक में दूसरे रंग में होने का ठीक गुण है।
FOO_struct के क्षेत्रों को एक मॉड्यूल में संशोधित किया जा सकता है और किसी अन्य मॉड्यूल को अभी भी प्रयोग करने योग्य होने के लिए recompiled करने की आवश्यकता नहीं है।
उस शैली के साथ मैं पहले से ही OOP (डेटा एनकैप्सुलेशन) के फायदों का एक बड़ा हिस्सा संभालता हूं। फ़ंक्शन पॉइंटर्स का उपयोग करके, विरासत की तरह कुछ को लागू करना और भी आसान है, लेकिन ईमानदारी से, यह वास्तव में केवल शायद ही उपयोगी है।
typedef struct FOO_type FOO_type
हेडर में शून्य टाइप करने के लिए करते हैं तो आपको टाइपिंग चेकिंग का अतिरिक्त लाभ मिलता है, जबकि अभी भी आपकी संरचना को उजागर नहीं किया गया है।
आप फ़ंक्शन पॉइंटर्स का उपयोग करके इसे नकली कर सकते हैं, और वास्तव में, मुझे लगता है कि सी ++ कार्यक्रमों को सी में संकलित करना सैद्धांतिक रूप से संभव है।
हालांकि, यह शायद ही कभी किसी भाषा को एक प्रतिमान का उपयोग करने के बजाय एक भाषा पर एक प्रतिमान को मजबूर करने के लिए समझ में आता है।
ऑब्जेक्ट ओरिएंटेड C, किया जा सकता है, मैंने उस प्रकार का कोड कोरिया में उत्पादन में देखा है, और यह सबसे भयानक राक्षस था जिसे मैंने वर्षों में देखा था (यह पिछले वर्ष (2007) जैसा था कि मैंने कोड देखा था)। तो हाँ यह किया जा सकता है, और हाँ लोगों ने इसे पहले भी किया है, और अभी भी इस दिन और उम्र में भी करते हैं। लेकिन मैं C ++ या ऑब्जेक्टिव-सी की सिफारिश करूंगा, दोनों अलग-अलग प्रतिमानों के साथ ऑब्जेक्ट ओरिएंटेशन प्रदान करने के उद्देश्य से C से जन्मी भाषाएँ हैं।
यदि आप आश्वस्त हैं कि आप जिस समस्या को हल करने का प्रयास कर रहे हैं, उसके लिए एक OOP दृष्टिकोण बेहतर है, तो आप इसे गैर-OOP भाषा के साथ हल करने का प्रयास क्यों करेंगे? ऐसा लगता है कि आप नौकरी के लिए गलत उपकरण का उपयोग कर रहे हैं। C ++ या कुछ अन्य ऑब्जेक्ट ओरिएंटेड C वेरिएंट भाषा का उपयोग करें।
यदि आप पूछ रहे हैं क्योंकि आप सी में लिखी गई पहले से मौजूद बड़ी परियोजना पर कोड करना शुरू कर रहे हैं, तो आपको अपने स्वयं के (या किसी और के) ओओपी प्रतिमानों को परियोजना के बुनियादी ढांचे में मजबूर करने की कोशिश नहीं करनी चाहिए। परियोजना में पहले से मौजूद दिशानिर्देशों का पालन करें। सामान्य तौर पर, स्वच्छ एपीआई और पृथक पुस्तकालय और मॉड्यूल एक साफ ओओपी- ईश डिजाइन होने की दिशा में एक लंबा रास्ता तय करेंगे ।
यदि, इस सब के बाद, आप वास्तव में OOP C कर रहे हैं, तो इसे पढ़ें (PDF)।
हाँ तुम कर सकते हो। लोग C ++ या Objective-C दृश्य में आने से पहले ऑब्जेक्ट ओरिएंटेड सी लिख रहे थे । C ++ और Objective-C दोनों, भागों में थे, C में प्रयुक्त कुछ OO अवधारणाओं को लेने का प्रयास करते हैं और उन्हें भाषा के भाग के रूप में औपचारिक रूप देते हैं।
यहाँ एक बहुत ही सरल प्रोग्राम है जो दिखाता है कि आप कैसे कुछ बना सकते हैं जो दिखता है-जैसा / एक तरीका है कॉल (ऐसा करने के बेहतर तरीके हैं। यह सिर्फ सबूत है कि भाषा अवधारणाओं का समर्थन करती है)।
#include<stdio.h>
struct foobarbaz{
int one;
int two;
int three;
int (*exampleMethod)(int, int);
};
int addTwoNumbers(int a, int b){
return a+b;
}
int main()
{
// Define the function pointer
int (*pointerToFunction)(int, int) = addTwoNumbers;
// Let's make sure we can call the pointer
int test = (*pointerToFunction)(12,12);
printf ("test: %u \n", test);
// Now, define an instance of our struct
// and add some default values.
struct foobarbaz fbb;
fbb.one = 1;
fbb.two = 2;
fbb.three = 3;
// Now add a "method"
fbb.exampleMethod = addTwoNumbers;
// Try calling the method
int test2 = fbb.exampleMethod(13,36);
printf ("test2: %u \n", test2);
printf("\nDone\n");
return 0;
}
जोड़ने के लिए थोड़ा OOC कोड:
#include <stdio.h>
struct Node {
int somevar;
};
void print() {
printf("Hello from an object-oriented C method!");
};
struct Tree {
struct Node * NIL;
void (*FPprint)(void);
struct Node *root;
struct Node NIL_t;
} TreeA = {&TreeA.NIL_t,print};
int main()
{
struct Tree TreeB;
TreeB = TreeA;
TreeB.FPprint();
return 0;
}
मैं इसे एक साल से खोद रहा हूं:
चूंकि Gobject सिस्टम का शुद्ध C के साथ उपयोग करना कठिन है, इसलिए मैंने O के साथ C की शैली को आसान बनाने के लिए कुछ अच्छे मैक्रोज़ लिखने की कोशिश की।
#include "OOStd.h"
CLASS(Animal) {
char *name;
STATIC(Animal);
vFn talk;
};
static int Animal_load(Animal *THIS,void *name) {
THIS->name = name;
return 0;
}
ASM(Animal, Animal_load, NULL, NULL, NULL)
CLASS_EX(Cat,Animal) {
STATIC_EX(Cat, Animal);
};
static void Meow(Animal *THIS){
printf("Meow!My name is %s!\n", THIS->name);
}
static int Cat_loadSt(StAnimal *THIS, void *PARAM){
THIS->talk = (void *)Meow;
return 0;
}
ASM_EX(Cat,Animal, NULL, NULL, Cat_loadSt, NULL)
CLASS_EX(Dog,Animal){
STATIC_EX(Dog, Animal);
};
static void Woof(Animal *THIS){
printf("Woof!My name is %s!\n", THIS->name);
}
static int Dog_loadSt(StAnimal *THIS, void *PARAM) {
THIS->talk = (void *)Woof;
return 0;
}
ASM_EX(Dog, Animal, NULL, NULL, Dog_loadSt, NULL)
int main(){
Animal *animals[4000];
StAnimal *f;
int i = 0;
for (i=0; i<4000; i++)
{
if(i%2==0)
animals[i] = NEW(Dog,"Jack");
else
animals[i] = NEW(Cat,"Lily");
};
f = ST(animals[0]);
for(i=0; i<4000; ++i) {
f->talk(animals[i]);
}
for (i=0; i<4000; ++i) {
DELETE0(animals[i]);
}
return 0;
}
यहाँ मेरा प्रोजेक्ट साइट है (मेरे पास en doc लिखने के लिए पर्याप्त समय नहीं है, हालाँकि चीनी में doc ज्यादा बेहतर है)।
जिम लार्सन की 1996 की सी बात में सी 312 प्रोग्रामिंग लंचटाइम सेमिनार में यहां सी: हाई और लो-लेवल सी का उपयोग करके विरासत का एक उदाहरण दिया गया है ।
C में OOP अवधारणाओं का उपयोग करने के लिए कौन से लेख या किताबें अच्छी हैं?
डेव हैन्सन के सी इंटरफेस और कार्यान्वयन है उत्कृष्ट कैप्सूलीकरण और नामकरण पर और समारोह संकेत के उपयोग पर बहुत अच्छा। डेव विरासत के अनुकरण की कोशिश नहीं करते हैं।
एक चीज जो आप करना चाहते हैं, वह एक्स विंडो के लिए Xt टूलकिट के कार्यान्वयन पर गौर करना चाहिए । यकीन है कि यह दाँत में लंबे समय से हो रहा है, लेकिन उपयोग किए जाने वाले कई ढांचे पारंपरिक सी के भीतर एक ओओ फैशन में काम करने के लिए डिज़ाइन किए गए थे। आम तौर पर इसका मतलब है कि यहां और वहां अप्रत्यक्षता की एक अतिरिक्त परत को जोड़ना और एक दूसरे पर बिछाने के लिए संरचनाओं को डिजाइन करना।
आप वास्तव में O के रास्ते में C पर इस तरह से बहुत कुछ कर सकते हैं, भले ही यह कुछ समय ऐसा लगता हो, OO अवधारणाओं ने वसंत के दिमाग से पूरी तरह से गठन नहीं किया था #include<favorite_OO_Guru.h>
। उन्होंने वास्तव में उस समय के कई स्थापित सर्वोत्तम अभ्यासों का गठन किया। OO भाषाएँ और प्रणालियाँ दिन के प्रोग्रामिंग ज़ेगेटिस्ट के केवल आसुत और प्रवर्धित भाग हैं।
प्रश्न का उत्तर 'हां, आप कर सकते हैं' है।
ऑब्जेक्ट-ओरिएंटेड C (OOC) किट उन लोगों के लिए है जो ऑब्जेक्ट-ओरिएंटेड तरीके से प्रोग्राम करना चाहते हैं, लेकिन अच्छे पुराने C पर भी चिपक जाते हैं। OOC लागू वर्गों, एकल और कई विरासत, अपवाद हैंडलिंग।
विशेषताएं
• केवल सी मैक्रोज़ और फ़ंक्शन का उपयोग करता है, कोई भाषा एक्सटेंशन की आवश्यकता नहीं है! (एएनएसआई-सी)
• अपने आवेदन के लिए आसान करने के लिए पढ़ा स्रोत कोड। चीजों को यथासंभव सरल बनाने के लिए देखभाल की गई थी।
• कक्षाओं का एकल वंशानुक्रम
• इंटरफेस और मिक्सिंस द्वारा एकाधिक वंशानुक्रम (संस्करण 1.3 से)
• अपवादों को लागू करना (शुद्ध C में!)
• कक्षाओं के लिए आभासी कार्य
• आसान वर्ग कार्यान्वयन के लिए बाहरी उपकरण
अधिक जानकारी के लिए, http://ooc-coding.sourceforge.net/ पर जाएं ।
ऐसा लगता है कि लोग सी + + शैली का अनुकरण करने की कोशिश कर रहे हैं। सी। मेरा उपयोग यह है कि ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग सी करना वास्तव में स्ट्रक्चर-ओरिएंटेड प्रोग्रामिंग कर रहा है। हालाँकि, आप लेट बाइंडिंग, इनकैप्सुलेशन और इनहेरिटेंस जैसी चीजें हासिल कर सकते हैं। विरासत के लिए आप स्पष्ट रूप से अपने उप-संरचना में आधार संरचनाओं के लिए एक सूचक को परिभाषित करते हैं और यह स्पष्ट रूप से कई विरासत का एक रूप है। आपको यह भी निर्धारित करना होगा कि क्या आपके
//private_class.h
struct private_class;
extern struct private_class * new_private_class();
extern int ret_a_value(struct private_class *, int a, int b);
extern void delete_private_class(struct private_class *);
void (*late_bind_function)(struct private_class *p);
//private_class.c
struct inherited_class_1;
struct inherited_class_2;
struct private_class {
int a;
int b;
struct inherited_class_1 *p1;
struct inherited_class_2 *p2;
};
struct inherited_class_1 * new_inherited_class_1();
struct inherited_class_2 * new_inherited_class_2();
struct private_class * new_private_class() {
struct private_class *p;
p = (struct private_class*) malloc(sizeof(struct private_class));
p->a = 0;
p->b = 0;
p->p1 = new_inherited_class_1();
p->p2 = new_inherited_class_2();
return p;
}
int ret_a_value(struct private_class *p, int a, int b) {
return p->a + p->b + a + b;
}
void delete_private_class(struct private_class *p) {
//release any resources
//call delete methods for inherited classes
free(p);
}
//main.c
struct private_class *p;
p = new_private_class();
late_bind_function = &implementation_function;
delete_private_class(p);
साथ संकलित करें c_compiler main.c inherited_class_1.obj inherited_class_2.obj private_class.obj
।
तो सलाह यह है कि शुद्ध सी शैली से चिपके रहना चाहिए और सी ++ शैली में मजबूर करने की कोशिश नहीं करनी चाहिए। इसके अलावा यह एक एपीआई के निर्माण का एक बहुत ही साफ तरीका है।
सी। में ओओपी पर एक और मोड़ के लिए http://slkpg.byethost7.com/instance.html देखें । यह सिर्फ देशी सी का उपयोग करके पुनर्संयोजन के लिए उदाहरण डेटा पर जोर देता है। मल्टीपल इनहेरिटेंस फ़ंक्शन रैपर्स का उपयोग करके मैन्युअल रूप से किया जाता है। प्रकार की सुरक्षा बनाए रखी जाती है। यहाँ एक छोटा सा नमूना है:
typedef struct _peeker
{
log_t *log;
symbols_t *sym;
scanner_t scan; // inherited instance
peek_t pk;
int trace;
void (*push) ( SELF *d, symbol_t *symbol );
short (*peek) ( SELF *d, int level );
short (*get) ( SELF *d );
int (*get_line_number) ( SELF *d );
} peeker_t, SlkToken;
#define push(self,a) (*self).push(self, a)
#define peek(self,a) (*self).peek(self, a)
#define get(self) (*self).get(self)
#define get_line_number(self) (*self).get_line_number(self)
INSTANCE_METHOD
int
(get_line_number) ( peeker_t *d )
{
return d->scan.line_number;
}
PUBLIC
void
InitializePeeker ( peeker_t *peeker,
int trace,
symbols_t *symbols,
log_t *log,
list_t *list )
{
InitializeScanner ( &peeker->scan, trace, symbols, log, list );
peeker->log = log;
peeker->sym = symbols;
peeker->pk.current = peeker->pk.buffer;
peeker->pk.count = 0;
peeker->trace = trace;
peeker->get_line_number = get_line_number;
peeker->push = push;
peeker->get = get;
peeker->peek = peek;
}
मुझे पार्टी में थोड़ी देर हो गई है, लेकिन मैं अपने अनुभव को विषय पर साझा करना चाहता हूं: मैं इन दिनों एम्बेडेड सामान के साथ काम करता हूं, और मेरे पास एकमात्र (विश्वसनीय) संकलक सी है, जिससे मैं ऑब्जेक्ट-ओरिएंटेड लागू करना चाहता हूं सी में लिखी मेरी एम्बेडेड परियोजनाओं में दृष्टिकोण
मैंने अभी तक देखे गए अधिकांश समाधान टाइपकास्ट का भारी उपयोग किया है, इसलिए हम टाइप सुरक्षा खो देते हैं: यदि आप कोई गलती करते हैं तो कंपाइलर आपकी मदद नहीं करेगा। यह पूरी तरह से अस्वीकार्य है।
आवश्यकताएँ जो मेरे पास हैं:
मैंने इस लेख में विस्तार से अपना दृष्टिकोण समझाया है: सी में ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग ; इसके अलावा, आधार और व्युत्पन्न वर्गों के लिए बॉयलरप्लेट कोड के ऑटोगेनेरेशन के लिए एक उपयोगिता है।
मैंने एक छोटी सी लाइब्रेरी बनाई जहाँ मैंने कोशिश की और मेरे लिए यह अच्छी तरह से काम करता है। इसलिए मैंने सोचा कि मैं अनुभव साझा करता हूं।
https://github.com/thomasfuhringer/oxygen
एकल वंशानुक्रम को आसानी से एक संरचना का उपयोग करके और इसे हर दूसरे बच्चे के वर्ग के लिए विस्तारित किया जा सकता है। मूल संरचना के लिए एक सरल कलाकार सभी वंशजों पर मूल तरीकों का उपयोग करना संभव बनाता है। जब तक आप जानते हैं कि एक चर इस तरह की एक वस्तु को पकड़े हुए एक संरचना को इंगित करता है जिसे आप हमेशा रूट क्लास में डाल सकते हैं और आत्मनिरीक्षण कर सकते हैं।
जैसा कि उल्लेख किया गया है, आभासी तरीके कुछ पेचीदा हैं। लेकिन वे करने योग्य हैं। चीजों को सरल रखने के लिए, मैं सिर्फ कक्षा विवरण संरचना में कार्यों की एक सरणी का उपयोग करता हूं जो कि प्रत्येक बच्चे की कक्षा की प्रतियां और जहां आवश्यक हो, व्यक्तिगत स्लॉट्स को फिर से खोलती है।
एकाधिक वंशानुक्रम लागू करने के लिए जटिल होगा और एक महत्वपूर्ण प्रदर्शन प्रभाव के साथ आता है। इसलिए मैं इसे छोड़ देता हूं। मैं इसे वास्तविक जीवन की परिस्थितियों को साफ-सुथरा बनाने के लिए काफी मामलों में वांछनीय और उपयोगी मानता हूं, लेकिन शायद 90% मामलों में एकल वंशानुक्रम जरूरतों को कवर करता है। और एकल विरासत सरल है और कुछ भी नहीं खर्च होता है।
इसके अलावा मुझे टाइप सेफ्टी की परवाह नहीं है। मुझे लगता है कि आपको प्रोग्रामिंग गलतियों से बचाने के लिए आपको कंपाइलर पर निर्भर नहीं होना चाहिए। और यह आपको केवल त्रुटियों के एक छोटे से हिस्से से ही ढाल देता है।
आमतौर पर, एक वस्तु उन्मुख वातावरण में आप स्मृति प्रबंधन को संभव तक सीमित करने के लिए संदर्भ गिनती को लागू करना चाहते हैं। इसलिए मैंने "ऑब्जेक्ट" रूट क्लास में एक संदर्भ गणना और कुछ मेमोरी को ढेर मेमोरी के आवंटन और निपटान के लिए रखा।
यह सब बहुत ही सरल और दुबला है और मुझे OO की अनिवार्यता देता है, बिना मुझे उस राक्षस से निपटने के लिए मजबूर करता है जो C ++ है। और मैं सी भूमि में रहने के लचीलेपन को बनाए रखता हूं, जो अन्य चीजों के बीच तीसरे पक्ष के पुस्तकालयों को एकीकृत करना आसान बनाता है।
मैं उद्देश्य-सी का उपयोग करने का प्रस्ताव करता हूं, जो सी का सुपरसेट है।
जबकि Objective-C 30 वर्ष पुराना है, यह सुरुचिपूर्ण कोड लिखने की अनुमति देता है।
हां, लेकिन मैंने कभी किसी को सी के साथ किसी भी तरह के बहुरूपता को लागू करने का प्रयास करते नहीं देखा।