Это все немного субъективно, но я бы начал с того, что отбросил стиль сокрытия указателей за typedef и намазывал на него какую-то «венгерскую нотацию». С этим согласится множество программистов на Си.
Итак, первое предложение состоит в том, чтобы пойти с
typedef struct DEVICE_s DEVICE_s;
А затем определите ваш непрозрачный интерфейс на основе DEVICE_s*
. Мало того, что легче читать, вы отфильтровывает запутывание, как вызывающий абонент, пытающийся передать p_DEVICE*
пользовательским функциям и т. Д., Потому что они не понимают, что у них уже есть указатель. (Win32 API сильно страдает от этой проблемы.)
Тогда ваш конструктор становится
DEVICE_s* DeviceManager_Ctor ( ...
И все функции-члены получат параметр DEVICE_s*
, а не p_DEVICE
по значению. Вызывающий должен будет объявлять указатели вместо объектов, давая им понять, что у них есть указатель на неполный тип и с чем они могут / не должны играть.
Далее вы можете удалить указатель, скрытый в указателе функции. Это не проблема, но приятно быть последовательным:
typedef DEVICE_s* DeviceManager_Ctor_t ( ...
Тогда ваши определения указателей на функции станут:
DeviceManager_Ctor_t* Ctor;
Вы можете отказаться от именования "fp", так как уже очевидно, что тип является указателем на функцию.
В качестве примечания я бы рекомендовал избегать имитации функций-членов C ++ с пометкой obj.member
. Потому что в C, без указателя this
, вы получите obj.member(&obj, ...)
, что отчасти избыточно.
Скорее просто примите, что C такой, какой он есть, и вызовите функции-члены как DeviceManager_Ctor(obj);
, где obj
объявлено как DEVICE_s* obj;
. Ключом к читаемому OO-коду является использование согласованного префикса исходного кода для всех функций, принадлежащих «классу», как вы уже это делаете: DeviceManager_
.