2 Stimmen

Abgleich von Klassen, Vererbung und C-Callbacks

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?

0voto

bk1e Punkte 23191

Könnte Ihr Callback eine Instanz auswählen, die auf a und/oder b ? Wenn ja, dann registrieren Sie Ihre Bibliotheksunterstützungsklassen in einer globalen/statischen Map und haben dann callbackADispatch() die richtige Instanz in der Karte zu finden.

Serialisierung Zugriff auf die Karte mit einem Mutex wäre ein vernünftiger Weg, um diese Thread-sicher zu machen, aber Vorsicht: wenn die Bibliothek hält alle Sperren, wenn es Ihren Callback aufruft, dann müssen Sie möglicherweise etwas mehr clever zu tun, um Deadlocks zu vermeiden, je nach Ihrer Sperre Hierarchie.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X