Подход, который я бы порекомендовал, состоит в том, чтобы посмотреть на какой-нибудь другой код C, использующий таблицу диспетчеризации, и посмотреть, как она структурирована. Конкретные примеры, о которых я знаю навскидку (возможно, не самые лучшие обучающие примеры, так как они просто случайное бесплатное программное обеспечение, над которым я работал), — это MIT Kerberos и Heimdal, оба из которых используют таблицы диспетчеризации повсюду. место и веб-сервер Apache и то, как он обрабатывает динамически загружаемые модули. Ни один из них не делает наследования, но добавить наследование относительно просто: вы видите, является ли метод, который вы пытаетесь вызвать, NULL, и если да, вы проверяете родительскую таблицу диспетчеризации для этого метода.
Краткая версия того, как обращаться с диспетчерской таблицей в C, заключается в том, что вы определяете структуру данных, аналогичную виртуальной таблице C++, которая содержит указатели на функции и какой-то способ выяснить, какой указатель использовать. Что-то типа:
typedef void (*dispatch_func)(void *);
struct dispatch {
const char *command;
dispatch_func callback;
};
— это суперуниверсальная версия, которая сопоставляет имена строковых методов с функциями, принимающими один анонимный указатель в качестве аргумента. Ваша фактическая таблица отправки будет состоять из таких массивов, как здесь (модифицированный пример, взятый из tinyleaf в исходном коде INN):
const struct dispatch commands[] = {
{ "help", command_help },
{ "ihave", command_ihave },
{ "quit", command_quit }
};
Очевидно, что чем больше вы знаете о функциях, тем более конкретным вы сможете сделать прототип и встроить в диспетчерскую таблицу другие критерии выбора (например, количество аргументов). (Фактический источник INN имеет минимальное и максимальное количество аргументов, передает структуру аргументов, а не просто void *, и включает описание команды в таблице отправки.)
Базовый код для поиска в диспетчерской таблице довольно прост. Предполагая, что у вас есть массив этих записей структуры отправки в vtable
и длину таблицы в length
, что-то вроде:
for (i = 0; i < length; i++)
if (strcmp(command, vtable[i].command) == 0) {
(*vtable[i].callback)(data);
return;
}
Чтобы реализовать наследование, вам понадобится родительский указатель, и если вы упадете с конца цикла, вы перейдете к родителю и повторите логику. (Очевидно, что это может быть полезным местом для рекурсивной функции.)
person
rra
schedule
31.03.2013