Frage

typedef void (FunctionSet::* Function)();

class MyFunctionSet : public FunctionSet
{
protected:
    void addFunctions()
    {
        addFunction(Function(&MyFunctionSet::function1));
    }

    void function1()
    {
        // Do something.
    }
};

Die addFunction Methode fügt die Funktion auf eine Liste in der Basisklasse,
die dann aufgezählt werden, um alle Funktionen zu nennen.

Gibt es eine Möglichkeit (weniger Schreibarbeiten) das Hinzufügen von Funktionen zu vereinfachen?

War es hilfreich?

Lösung

Sieht aus wie Sie ein Mitglied Funktionszeiger auf eine Funktion der abgeleiteten Klasse auf eine Elementfunktion Zeiger auf eine Funktion der Basisklasse zuordnen. Nun, das ist verboten, weil es ein Loch in dem Art-System eröffnet. Es kommt zu einer Überraschung (zumindest für mich, das erste Mal, dass ich gehört, dass). Lesen Sie diese Antwort Warum.

Ihre eigentliche Frage beantworten - ich würde eine Vorlage machen addFunction:

void addFunctions() {
    addFunction(&MyFunctionSet::function1);
}

Ändern addFunction in der Basis-Klasse folgt aus:

template<typename Derived>
void addFunction(void(Derived::*f)()) {
    myFunctions.push_back(static_cast<Function>(f));
}

Bessere Nutzung static_cast, denn es wird Ihnen sagen, wenn Derived tatsächlich nicht von FunctionSet abgeleitet.

Andere Tipps

Können Sie erklären, was Sie versuchen, dies zu erreichen, indem Sie?

Dies scheint ein ziemlich schlechtes Design, können Sie nicht haben eine abstrakte Klasse ( „c ++ Schnittstelle“) wie „Berechenbare“, die ein rein virtuell function1 hat, Unterklasse Berechenbare für jede Implementierung, und dann haben MyFunctionSet einen Satz zu halten berechenbare?

Gibt es einen bestimmten Grund, warum Sie Funktionszeiger verwenden?

Also, neige ich dazu, mit Uri anderer Meinung zu sein, etwas.

Wenn Sie die Beobachter-Muster implementieren, was Sie wollen in der Lage sein zu sagen:

"Wenn das Objekt X Y der Fall ist, möchte ich Code Z auszuführen".

Möchten Sie einen Ansatz, der allein auf einer abstrakten Klasse ist nicht der beste Weg, das zu tun. eine separate Klasse erfordert (insbesondere in C ++) für jeden Event-Handler ist übertrieben. Wenn Sie von Java kommen, das ist, wie sie alles tun. Allerdings Java hat zwei Funktionen, die dies nur etwas ärgerlich machen: anonyme Klasse, und „Instanz“ Elementklassen. Auf diese Weise können Sie mehrere Handler für mehrere Ereignisse in der gleichen Klasse definieren. Sie haben die Methoden mit „Klasse {“ Präfix, aber Sie können es tun.

C ++ hat weder anonyme Klassen oder „Instanz“ Elementklassen. Dies macht für Veranstaltungen eine abstrakte Klasse mit vielen umständlichen, wenn Sie mehrere Handler haben, den Staat teilen müssen. Sie haben das Äquivalent von Verschluss Generation von Hand zu tun, das ist ziemlich schnell ziemlich irritierend bekommen kann.

.NET verwendet Delegaten für Ereignisbehandlung, die im Grunde sichere Funktionszeiger-Typ ist. Sie machen den Code für Veranstaltungen sehr einfach handhaben. Im Gegensatz zu Funktionszeiger in C ++, aber vereint eine Delegierten Mitglied Funktionszeiger und statischen Funktionszeiger. Grundsätzlich kann es die „dieses“ Parameter eines Mitglieds Funktion Curry, ein Funktionszeiger zu verlassen, die genau wie eine statische Funktion Zeiger aussieht. Dies bedeutet, dass die Art des Objekts, die Ereignisbehandlung ist nicht Teil der Veranstaltung „Schnittstelle“. Das macht es sehr flexibel ist.

Sie können das direkt nicht mit C ++ Mitglied Funktionszeiger, weil die „diese“ Art ein Teil der Funktion Zeigertyp endet als, damit Ihre Handler limitierend nur innerhalb der aktuellen Klasse erscheinen.

Die beste Lösung für C ++ ist ein Hybrid zwischen den beiden. Was Sie wollen, ist eine generische Schnittstelle wie folgt:

class EventHandler
{
public:
    virtual void Handle() = 0;
};

Und dann eine Implementierung für Member-Funktionen wie folgt

template <class T>
class MemberFuncEventHandler : public EventHandler
{
public:


    MemberFuncEventHandler(T * pThis, void (T::*pFunc)()) : m_pThis(pThis), m_pFunc(pFunc)
    {
    }

    void Handle()
    {
        (m_pThis->*m_pFunc)();
    } 
private:
    T* m_pThis;
    void (T::*m_pFunc)();
};

template <class T>
EventHandler * Handler(T * pThis, void (T::*pFunc)())
{
    return new MemberFuncEventHandler<T>(pThis, pFunc);
}

Sie können auch in ähnlicher Weise eine Handler-Klasse für statische Methoden definieren. Dann können Sie einfach Dinge tun, wie folgt aus:

Handlers += Handler(obj, &(c1::foo));
Handlers += Handler(obj, &(c2::bar));
Handlers += Handler(blaa); // for static methods...

Sie können den Additionsoperator überlasten, nehme ich an.

Wenn Sie versuchen, ein Callback-System oder etwas zu machen, würde ich die Boost.Signals Bibliothek empfehlen. Im Grunde ist es Aggregate Funktionen und ruft die Funktionsgruppe auf Befehl (wie jede andere Signalbibliothek), aber es ist auch mit Boost.Bind und Boost.Function zu arbeiten entworfen, die genial sind.

Beispiel:

using boost::function
using boost::bind
using boost::signal

void some_other_func();    

Foo a;
Bar b;

signal<void()> sig;

sig.connect(bind(&Foo::foo,&a));
sig.connect(bind(&Bar::bar,&b));
sig.connect(some_other_func);

sig(); // calls -> a.foo(), b.bar(), some_other_func()

Auch unterstützt blocking, anspruchsvolles Verbindungsmanagement und andere nette Dinge.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top