2013-03-31 5 views
7

का उपयोग कर मैं सीगतिशील प्रेषण आभासी विधि तालिका

में गतिशील प्रेषण को लागू करने

मैं सी सीख रहा हूँ और अभ्यास के रूप में, मैं जावा से अनुवाद करना चाहते हैं के लिए एक संकेत (अधिमानतः अच्छा उदाहरण द्वारा) को खोजने के लिए आशा करता हूं गतिशील प्रेषण वर्चुअल विधि तालिका का उपयोग कर सी।

उदाहरण के लिए मैं एक जावा कोड है:

abstract class Foo { 
    public abstract int val(); 
    public abstract Boolean error(); 
} 

class Fail extends Foo { 
    public int val(){ return 0;} 
    public Boolean error(){return true;} 
} 

class IntFoo extends Foo { 
    int v; 
    public IntFoo(int value){this.value=v;} 
    public int val(){ return v;} 
    public Boolean error(){return False;} 
} 

और मैं सिर्फ इस तरह कुछ बुनियादी सामान उसका अनुवाद कर सकें:

typedef struct Foo{ 
    void(**vtable); 
}Foo; 

typedef struct Fail{ 
    void(**vtable); 
    struct Foo inherited; 
}Fail; 

typedef struct IntFoo{ 
    void(**vtable); 
    struct Foo inherited; 
}IntFoo; 

मैं इस वजह से मैं नहीं पूरा करने के लिए प्रयास करने के दौरान अटक कर रहा हूँ पता:

  1. सी में इन विधियों को कैसे परिभाषित करें।
  2. vtable में इन विधियों का पता सेट करें ताकि संकलक कॉल करने के लिए सही विधि को पहचान सके।
  3. इसे काम करने के लिए परिभाषित करने के लिए और क्या करना है।
+0

एक स्क्वायर छेद में एक गोल पेग को स्क्विश करने की कोशिश करने के बजाय - एक गैर-ओओपी भाषा पर ओओपी संरचना को मजबूर करने का प्रयास करने के लिए, मैं सी ++ का उपयोग करता हूं और इसके लिए सी नहीं। –

+3

@ होवरक्राफ्टफुलऑफेल मैं इसे केवल सी में करने के लिए देख रहा हूं क्योंकि मुझे अपने प्रोफेसर द्वारा करने के लिए कहा जाता है। – Solix

+1

* इस प्रकार की सामग्री के लिए स्रोत * [ooc.pdf] है (http://www.cs.rit.edu/~ats/books/ooc.pdf) [एक्सेल टोबीस श्राइनर] द्वारा (http: // www .cs.rit.edu/~ एटीएस/पुस्तकों /)। –

उत्तर

3

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

सामान्य रूप से सी में प्रेषण तालिका को संभालने के लिए संक्षिप्त संस्करण यह है कि आप सी ++ vtable की तरह एक डेटा संरचना को परिभाषित करते हैं, जिसमें फ़ंक्शन पॉइंटर्स होते हैं और यह पता लगाने के लिए कि कौन सा पॉइंटर उपयोग करना है। की तरह कुछ:

typedef void (*dispatch_func)(void *); 
struct dispatch { 
    const char *command; 
    dispatch_func callback; 
}; 

सुपर जेनेरिक वर्जन है, जो काम करता है कि एक तर्क के रूप में एक भी गुमनाम सूचक लेने के लिए स्ट्रिंग विधि के नाम नक्शे है।

const struct dispatch commands[] = { 
    { "help", command_help }, 
    { "ihave", command_ihave }, 
    { "quit", command_quit } 
}; 

जाहिर है, जितना अधिक आप कार्यों के बारे में पता है, और अधिक विशिष्ट आप कर सकते हैं: आपका वास्तविक प्रेषण तालिका इन की एक सरणी, इस तरह (INN स्रोत में tinyleaf से लिया एक संशोधित उदाहरण) हो जाएगा प्रोटोटाइप, और आप प्रेषण तालिका में अन्य चयन मानदंड (जैसे तर्कों की संख्या) को एम्बेड कर सकते हैं। (वास्तविक आईएनएन स्रोत में न्यूनतम और अधिकतम तर्क गणना होती है, केवल शून्य के बजाय तर्कों की संरचना में गुजरती है, और प्रेषण तालिका में कमांड विवरण शामिल है।)

प्रेषण तालिका खोजने के लिए मूल कोड सुंदर है सरल। आप यह मानते हुए है vtable में उन लोगों के प्रेषण struct प्रविष्टियों की एक सरणी और length में मेज की लंबाई, की तरह कुछ:

for (i = 0; i < length; i++) 
    if (strcmp(command, vtable[i].command) == 0) { 
     (*vtable[i].callback)(data); 
     return; 
    } 

विरासत को लागू करने के लिए, आप माता-पिता सूचक की आवश्यकता होगी, और यदि आप के अंत से गिर जाते हैं लूप, आप माता-पिता के पास जाते हैं और तर्क दोहराते हैं। (जाहिर है, यह एक पुनरावर्ती समारोह के लिए एक उपयोगी जगह हो सकती है।)

5

ऐसा करने का कोई आसान तरीका नहीं है। फिर भी आप मैन्युअल रूप से कर सकते हैं कि सी ++ कंपाइलर क्या कर रहा है।आपके मामले में इस तरह दिखेगा: विचार

typedef struct vtable_Fail 
{ 
    int (*val)(struct Fail *this_pointer); 
    bool (*error)(struct Fail *this_pointer); 
} vtable_Fail; 

typedef struct vtable_IntFoo 
{ 
    int (*val)(struct IntFoo *this_pointer); 
    bool (*error)(struct IntFoo *this_pointer); 
} vtable_IntFoo; 

int Fail_val(struct Fail *this_pointer) 
{ 
    return 0; 
} 

... 

void IntFoo_ctor(struct IntFoo *this_pointer, int value) 
{ 
    this_pointer->v = value; 
} 

int IntFoo_val(struct IntFoo *this_pointer) 
{ 
    return this_pointer->v; 
} 

... 

struct Fail 
{ 
    vtable_Fail *vtable; 
}; 

struct IntFoo 
{ 
    vtable_IntFoo *vtable; 
    int v; 
}; 

है कि प्रत्येक struct एक साथी vtable struct कि सभी आभासी तरीकों कि इस struct लागू करने के लिए संकेत संग्रहीत करता है होना चाहिए। Vtable structs में केवल एक उदाहरण है। उन्हें स्थैतिक स्मृति में रहना चाहिए और उन्हें फंक्शंस के साथ कार्यों में शामिल किया जाना चाहिए। इन पॉइंटर्स को प्रत्येक विशेष संरचना के लिए आवश्यक तरीके से वर्चुअल विधियों को लागू करना चाहिए। Structs स्वयं कई उदाहरण हो सकता है। उदाहरण में Vtable डेटा फ़ाइल्स को अपनी कक्षा के स्थैतिक vtable संरचना को इंगित करना चाहिए।

पैरामीटर this_pointer उदाहरण के पते को पास करता है। इसे मैन्युअल रूप से पारित किया जाना चाहिए। यह दिन के अंत में सी है।

नोट आपको vtable संरचनाओं, init vtable पॉइंटर्स इत्यादि आवंटित करने की आवश्यकता है और आपको इसे अपने कोड के साथ मैन्युअल रूप से करने की आवश्यकता है।

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