полиморфизм функций
От: Alexander Pazdnikov  
Дата: 01.04.07 11:18
Оценка:
Доброго времени суток.

Реализован полиморфизм функций на С++ в стиле С, не в стиле С++.
Т.е. пришел пакет, определили номер запрошенной функции, получили указатель на реализацию соответсвующей функции и вызвали ее по указателю.

Как можно сделать более красиво абстракцию вызова функции-обработки, заместо
retval = (this->*(mbfPtr->funcPtr))(rcv_buf, rcv_size, snd_buf, snd_size, dev_no);

Использовал и такой способ
swith(<номер функции>){
case 1: session_close(...) break;
case 2: session_open(...) break;
/// и т.д.
default: <создание ответа ошибки>;
}
но как-то уж смотрелось это все некрасиво

Привожу сам вид кода

#include <stdint.h>
// Структура данных функции
class FN_SPEC
{
public:
    uint8_t    func_id;  // номер функции
    int (MyClass::*funcPtr)(uint8_t *, uint32_t *, uint8_t *, uint32_t *, int32_t);
    // и другие параметры
};

FN_SPEC    func_spec[] = {
    {1, &MyClass::session_close,},
    {2, &MyClass::session_open,},
    {3, &MyClass::read_output_status,},
    {4, &MyClass::read_input_status,},
    
    // и т.д. 127 функций
    // End-Terminator
    {0, NULL}
}

// Функция возвращает указатель на структуру данных функции
// по ее  номеру, или NULL если такого номера нет в массиве
// данных функций.
//
FN_SPEC    *get_func_struct(uint8_t func_id)
{
    int    i;

    for(i = 0; func_spec[i].func_id != 0; i++){
        if (func_spec[i].func_id == func_id)
            /* Нашли структуру данных функции, возвращаем указатель на нее */
            return func_spec + i;
    }
    return NULL;
}

class MyClass
{
public:
    /// функция - обертка для вызова соответствующей обработки функций протокола
    int call_function(uint8_t *rcv_buf, uint32_t *rcv_size, uint8_t *snd_buf, uint32_t *snd_size, int32_t dev_no);
public:
    /// \name Функции протокола
    /// Входные параметры для всех функций одинаковые
    /// \param[in] rcv_buf буфер принятого пакета \param[in] rcv_size размер принятого пакета
    /// \param[out] snd_buf буфер пакета ответа \param[out] snd_size размер пакета ответа
    /// \param[in] dev_no номер устройства обработки пакета
    ///@{
    int sessioon_close(uint8_t *rcv_buf, uint32_t *rcv_size, uint8_t *snd_buf, uint32_t *snd_size, int32_t dev_no);
    int session_open(uint8_t *rcv_buf, uint32_t *rcv_size, uint8_t *snd_buf, uint32_t *snd_size, int32_t dev_no);
    int read_output_status(uint8_t *rcv_buf, uint32_t *rcv_size, uint8_t *snd_buf, uint32_t *snd_size, int32_t dev_no);
    int read_input_status(uint8_t *rcv_buf, uint32_t *rcv_size, uint8_t *snd_buf, uint32_t *snd_size, int32_t dev_no);
    // и другие функции
    ///@}
public:
    uint8_t rcv_buf[MAX_PACKET_SIZE], snd_buf[MAX_PACKET_SIZE]
}

int MyClass::call_function(uint8_t *rcv_buf, uint32_t *rcv_size, uint8_t *snd_buf, uint32_t *snd_size, int32_t dev_no)
{
    int retval = RET_OK;
    FN_SPEC *mbfPtr = NULL;
    
    try{
        // получим справочную структуру данных функции
        if (!(mbfPtr = get_func_struct(rcv_buf[1]))){
            throw(ERR_INVALID_FUNCTION);
        }

        // в зависимости от номера функции в пакете
        // запускаем на обработку пакета соответствующую функцию
        // выполним соотвествующую функцию
        // если она задана
        if (mbfPtr->funcPtr){
            /// ВОТ ОНО КЛЮЧЕВОЕ, КОТОРОМУ И ПРИНАДЛЕЖИТ ВОПРОС
            /// Искусственный полиморфизм вызова функции по указателю
            /// Как можно сделать более карасиво и эллегантнее????????????????
            retval = (this->*(mbfPtr->funcPtr))(rcv_buf, rcv_size, snd_buf, snd_size, dev_no);
        }else{
            throw(ERR_FUNCTION_NOT_IMPLEMENTED);
        }
        
        // все в порядке, отправляем ответ
        retval = MB_OK;
        
    }catch(int &e){
        // тут обработка ответа - ошибки
    }

    // выход, чтобы отправить ответ
    return retval;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.