В моем проекте на C ++ я решил использовать библиотеку C. В моем рвении иметь хорошо продуманный и простой дизайн я закончил тем, что сделал небольшой шаг вперед. Частью моего требования к дизайну является то, что я могу легко поддерживать несколько API и библиотек для определенной задачи (прежде всего, из-за моего требования к кроссплатформенной поддержке). Итак, я решил создать абстрактный базовый класс, который бы равномерно обрабатывал данный набор библиотек.
Рассмотрим это упрощение моего дизайна:
class BaseClass
{
public:
BaseClass() {}
~BaseClass() {}
bool init() { return doInit(); }
bool run() { return doWork(); }
void shutdown() { destroy(); }
private:
virtual bool doInit() = 0;
virtual bool doWork() = 0;
virtual void destroy() = 0;
};
И класс, который наследует от него:
class LibrarySupportClass : public BaseClass
{
public:
LibrarySupportClass()
: BaseClass(), state_manager(new SomeOtherClass()) {}
int callbackA(int a, int b);
private:
virtual bool doInit();
virtual bool doWork();
virtual void destroy();
SomeOtherClass* state_manager;
};
// LSC.cpp:
bool LibrarySupportClass::doInit()
{
if (!libraryInit()) return false;
// the issue is that I can't do this:
libraryCallbackA(&LibrarySupportClass::callbackA);
return true;
}
// ... and so on
Проблема, с которой я столкнулся, состоит в том, что, поскольку это библиотека C, я должен предоставить C-совместимый обратный вызов в форме int (*)(int, int)
, но библиотека не поддерживает дополнительный указатель пользовательских данных для этих обратные вызовы. Я бы предпочел бы делать все эти обратные вызовы внутри класса, потому что класс несет объект состояния.
То, что я в итоге сделал, это ...
static LibrarySupportClass* _inst_ptr = NULL;
static int callbackADispatch(int a, int b)
{
_inst_ptr->callbackA(a, b);
}
bool LibrarySupportClass::doInit()
{
_inst_ptr = this;
if (!libraryInit()) return false;
// the issue is that I can't do this:
libraryCallbackA(&callbackADispatch);
return true;
}
Это явно будет плохо, если библиотека LibrarySupportClass будет создана более одного раза, поэтому я подумал об использовании одноэлементного дизайна, но по этой одной причине я не могу оправдать этот выбор.
Есть ли лучший способ?