Доброго времени суток.
Реализован полиморфизм функций на С++ в стиле С, не в стиле С++.
Т.е. пришел пакет, определили номер запрошенной функции, получили указатель на реализацию соответсвующей функции и вызвали ее по указателю.
Как можно сделать более красиво абстракцию вызова функции-обработки, заместо
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;
}