2013-03-31 4 views
7

Я в надежде найти подсказку (желательно хорошим примером) для осуществления динамической диспетчеризации в С.Динамическая отправка в С использованием виртуальной таблицы метод

Я учусь C и как показывает практика, я хочу перевести с Java на C, используя таблицу виртуальных методов динамической отправки.

, например, у меня есть код Java:

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. Как определить эти методы в c.
  2. Задайте адрес этих методов в vtable, чтобы компилятор распознал правильный метод вызова.
  3. Что еще нужно определить, чтобы заставить его работать.
+0

Вместо того, чтобы пытаться скрутить круглую привязку в квадратное отверстие - чтобы попытаться заставить структуру ООП на языке, отличном от ООП, я бы использовал C++, а не C для этого. –

+3

@HovercraftFullOfEels Я ищу, чтобы сделать это в c только, как меня просят сделать мой профессор. – Solix

+1

* Источник * для этого материала [ooc.pdf] (http://www.cs.rit.edu/~ats/books/ooc.pdf) [Axel Tobias Schreiner] (http: // www .cs.rit.edu/~ ATS/книги /). –

ответ

3

Подход, который я бы рекомендовал, - это посмотреть на другой код C, который использует таблицу диспетчеризации и посмотреть, как он структурирован. Конкретные примеры, которые я знаю из головы (возможно, не лучшие примеры обучения, поскольку они просто случайное бесплатное программное обеспечение, над которым я работал) являются MIT Kerberos и Heimdal, оба из которых используют таблицы отправки по всему миру место и веб-сервер Apache и то, как он обрабатывает динамически загружаемые модули. Ни одно из них не наследует, но наследование относительно просто добавить: вы видите, является ли метод, который вы пытаетесь вызвать, NULL, и если это так, вы проверяете родительскую таблицу рассылки для этого метода.

Краткая версия того, как обрабатывать таблицу рассылки в C, заключается в том, что вы определяете структуру данных, сродни C++ vtable, которая содержит указатели на функции и способ определения того, какой указатель использовать. Что-то вроде:

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

является супер-универсальным вариантом, который отображает имена методов строковых функции, которые принимают один анонимный указатель в качестве аргумента. Фактическая таблица доставки будет массив из них, как это (модифицированный пример, взятый из tinyleaf в источнике МНН):

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

Очевидно, что чем больше вы знаете о функциях, тем более конкретнее вы можете сделать прототип, и вы можете встроить другие критерии выбора (например, количество аргументов) в таблицу рассылки. (Фактический источник INN имеет минимальное и максимальное количество аргументов, переходит в структуру аргументов, а не только void *, и включает описание команды в таблице рассылки.)

Базовый код для поиска таблицы рассылки довольно просто. Предполагая, что вы массив этих записей диспетчерская STRUCT в vtable и длина стола в length, что-то вроде:

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

Для реализации наследования, вам нужно будет родительский указатель, и если вы упадете конец цикл, вы переходите к родительскому и повторяете логику. (Очевидно, это может быть полезным местом для рекурсивной функции.)

5

Нет простого способа сделать это. Тем не менее вы можете вручную сделать то, что делает компилятор C++.В вашем случае это будет выглядеть так:

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

Идея заключается в том, что каждая структура должна иметь сопроводительный виртуальные таблицы структуру, которая хранит указатели на все виртуальные методы, которые Эта структура реализует. Структуры Vtable имеют только один экземпляр каждый. Они должны находиться в статической памяти, и их следует использовать с указателями на функции. Эти указатели должны реализовывать виртуальные методы таким образом, который необходим для каждой конкретной структуры. Сами структуры могут иметь много экземпляров. Параметры данных Vtable в экземпляре должны указывать на статическую структуру vtable своего класса.

Параметр this_pointer передает адрес экземпляра. Его следует передавать вручную. Это C в конце дня.

Обратите внимание, что вам нужно выделить vtable-структуры, init vtable-указатели и т. Д. И вам нужно сделать все это вручную с помощью собственного кода.

 Смежные вопросы

  • Нет связанных вопросов^_^