2009-03-04 4 views
2

Angenommen, ich habe einige Code wie folgt:Ich muss einen einfachen Rückruf in C++ erstellen? Sollte ich die boost :: Funktion benutzen?

class Visitor { 
    public: 
     Visitor(callBackFunction) {} 
     void visit() { 
      //do something useful 
      invokeCallback(); 
     } 
} 

class ClassThatCanBeVisited { 
    Visitor &visitor; 

    public: 
     ClassThatCanBeVisited(Visitor &_visitor) : visitor(_visitor){} 
     void someUsefulMethod() { 
      int data= 42; 
      visitor.visit(data); 
     } 
}; 


void callBackFunction() { 
    //do something useful in the context of the Main file 
} 
int main() { 
    Visitor visitor; 
    ClassThatCanBeVisited foo(visitor); 
    foo.someUsefulMethod(); 
} 

Ich brauche einen einfachen Rückruf zu erstellen, wann immer der Besuch :: Besucher genannt wird() aufgerufen wird. Ich weiß, dass ich den Code des Callbacks wahrscheinlich in meinen Besucher einfügen sollte, aber es ist in einem anderen Kontext, also würde ich die CallBackFunction() an den Besucher weitergeben, damit er meine Callback-Funktion aufrufen konnte.

Ich suchte Sachen auf dem Netz und sah boost :: Funktion, aber C++ hat bereits die grundlegenden functors.

Welches sollte ich für eine bessere Klarheit des Codes verwenden? Der Rückruf wird eine einfache void() Funktion sein, aber es könnte wachsen, man weiß ja nie die Zukunft :)

Was ist der empfohlene Weg, dies zu tun?

Antwort

4

Sie können Callback-Schnittstelle und ihre Hierarchie verwenden, wenn Sie nicht boost :: Funktion verwendet werden soll.

class VisitorCallback 
{ 
public: 
    virtual void handle(const Visitor&) = 0; 
}; 

Wenn Sie oder boost :: function verwenden - es verwenden, ist es eine gute Möglichkeit, all diese Callback-Klassen loszuwerden.

Edit:
@edisongustavo:

boost :: function und boost :: bind wird nicht wahrscheinlich Ihren Code besser lesbar machen. Aber es gibt Ihnen die Möglichkeit, freie Funktionen (ich meine Funktionen aus der Klasse und statische Klassenfunktionen) als Callback sowie vorhandene Funktionen jeder Klasse zu übergeben.

Mit Boost-Funktionen können Sie Funktionen mit zum Beispiel 2 Parameter wie Rückruf, die nur einen Parameter erwarten passieren.

Aber noch einmal, dies wird Ihren Code nicht lesbarer machen, es sei denn, Ihr ganzes Team kennt und befürwortet Boost.

+0

Das ist die übliche Art und Weise, wie ich Dinge mache (da ich aus Java komme), aber ich sehe diese Rückrufe nicht als eine gute Sache (zu viele Klassen, jeder sagt boost :: function ist besser, etc.) Also in welcher Weise würde boost :: bind meinen Code lesbarer machen? –

+0

boost :: function befreit Sie davon, von einer Basisklasse zu erben, nur um einen Rückruf zu haben. Es befreit Sie auch davon, durch den Funktionsnamen begrenzt zu werden. Im Wesentlichen kann es verwendet werden, um die Kopplung zu verringern. –

+0

+1 auf den Boost :: Funktionsteil, aber ich mag nicht die var_args Ansatz. Es ist auf verschiedene Arten begrenzt: Sie verlieren Typ Sicherheit, Anrufer und Angerufene müssen sich auf ein Ende der Argumentliste Token und nicht jede Klasse kann durch Ellipse übergeben werden (nur PODs, wenn ich mich richtig erinnere) –

7

Ja Boost :: Funktion würde dies gut tun. Das ist eine sehr häufige Verwendung davon. Sie müssen boost :: bind verwenden, um die Instanz an die Elementfunktion zu binden.

func = boost::bind(&MyClass::CallbackFunc, this); 

wäre, wie Sie das innerhalb der Klasse tun würden.

Seien Sie sicher, dass die „this“ verschwinden oder nicht Ihre Boost-Funktion wird irgendwo in der Mitte einig Boost-Header zum Absturz bringen.

+0

Haben "this" den boost :: shared_from_this implementiert und einen schwachen Zeiger in der Bindung gespeichert? –

1

Die obigen Antworten sind großartig, aber ich möchte nur etwas hervorheben, das Sie in Ihrer Frage erwähnt haben, was immer noch relevant ist für Ihre Wahl zwischen C++ - Callback-Objekten (in Mykola's Antwort) und Boost.

„der Rückruf wird eine einfache void() Funktion sein, aber es könnte wachsen, man weiß ja nie die Zukunft :)“

Dies ist wahrscheinlich der schlechteste Grund, um zusätzliche, unnötige Funktionalität - das ist " nur für den Fall, dass Sie es brauchen ". Wenn du es nicht weißt - dann tu nicht mehr als nötig, die Wahrscheinlichkeit ist groß, dass deine Vermutung sowieso falsch ist, besonders wenn du es brauchst.

Auf der anderen Seite, wenn Sie wissen, dass es sehr wahrscheinlich ist, benötigen Sie die Funktionalität sehr bald, dann könnte es sich lohnen, es hinzuzufügen.

Noch einmal wiederholen, was Mykola gesagt hat - wenn Sie bereits Boost in Ihrem Projekt haben und Ihr Team es mag, dann benutzen Sie das, aber sonst ist es vielleicht zu viel.

+0

Ich stimme diesem Ansatz zu. Es ist ein weiterer Grund, warum ich boost :: function benutzt habe. Es ist einfach, entkoppelt die Implementierung und so weiter. Das Erstellen einer ganz neuen Klasse mit einer einfachen void() - Funktion schien für dieses Problem übertrieben zu sein, aber ich wollte keinen Funktionszeiger. Die boost :: Funktion hat also sehr gut funktioniert. Und ich musste eigentlich die Parameter der Funktion erhöhen, also half es mir zweimal –