In meinem C++-Projekt habe ich mich für die Verwendung einer C-Bibliothek entschieden. In meinem Eifer, ein gut abstrahiertes und einfaches Design zu haben, habe ich mich ein wenig verrannt. Ein Teil meiner Designanforderung besteht darin, dass ich problemlos mehrere APIs und Bibliotheken für eine bestimmte Aufgabe unterstützen kann (in erster Linie aufgrund meiner Anforderung nach plattformübergreifender Unterstützung). Also entschied ich mich, eine abstrakte Basisklasse zu erstellen, die eine bestimmte Auswahl an Bibliotheken einheitlich behandeln würde.
Betrachten Sie diese Vereinfachung meines Entwurfs:
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;
};
Und eine Klasse, die von ihr erbt:
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
Das Problem, auf das ich gestoßen bin, ist, dass, da es sich um eine C-Bibliothek handelt, ich einen C-kompatiblen Rückruf der Form bereitstellen muss int (*)(int, int)
, aber die Bibliothek unterstützt keinen zusätzlichen Userdata-Zeiger für diese Callbacks. Ich würde lieber alle diese Rückrufe innerhalb der Klasse durchführen, da die Klasse ein Statusobjekt enthält.
Was ich letztendlich getan habe, ist...
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;
}
Dies wird eindeutig Bad Things(TM) tun, wenn LibrarySupportClass mehr als einmal instanziiert wird, so dass ich erwog, das Singleton-Design zu verwenden, aber aus diesem einen Grund kann ich diese Wahl nicht rechtfertigen.
Gibt es einen besseren Weg?