Was ist die allgemeine Idee eines Delegaten in C ++? Was sind sie, wie werden sie verwendet und wofür werden sie verwendet?
Ich würde sie gerne zuerst auf eine Art „Black Box“ kennenlernen, aber ein bisschen Information über die Eingeweide dieser Dinge wäre auch großartig.
Dies ist nicht C ++ in seiner reinsten oder saubersten Form, aber ich stelle fest, dass die Codebasis, in der ich arbeite, sie im Überfluss enthält. Ich hoffe, sie genug zu verstehen, damit ich sie einfach verwenden kann und nicht in die schreckliche Schrecklichkeit verschachtelter Vorlagen eintauchen muss.
Diese beiden Artikel von The Code Project erklären, was ich meine, aber nicht besonders prägnant:
c++
delegates
delegation
Sir Yakalot
quelle
quelle
delegate
ist im C ++ - Sprachgebrauch kein gebräuchlicher Name. Sie sollten der Frage einige Informationen hinzufügen, um den Kontext einzuschließen, in dem Sie sie gelesen haben. Beachten Sie, dass das Muster zwar häufig vorkommt, die Antworten jedoch unterschiedlich sein können, wenn Sie über Delegate im Allgemeinen oder im Kontext von C ++ CLI oder einer anderen Bibliothek mit einer bestimmten Implementierung von Delegate sprechen .Antworten:
Sie haben eine unglaubliche Anzahl von Möglichkeiten, um Delegierte in C ++ zu erreichen. Hier sind diejenigen, die mir in den Sinn gekommen sind.
Option 1: Funktoren:
Ein Funktionsobjekt kann durch Implementierung erstellt werden
operator()
Option 2: Lambda-Ausdrücke (nur C ++ 11 )
Option 3: Funktionszeiger
Option 4: Zeiger auf Mitgliedsfunktionen (schnellste Lösung)
Siehe Fast C ++ Delegate (im Code-Projekt ).
Option 5: std :: function
(oder
boost::function
wenn Ihre Standardbibliothek dies nicht unterstützt). Es ist langsamer, aber am flexibelsten.Option 6: Bindung (mit std :: bind )
Ermöglicht das Einstellen einiger Parameter im Voraus, um beispielsweise eine Mitgliedsfunktion aufzurufen.
Option 7: Vorlagen
Akzeptieren Sie alles, solange es mit der Argumentliste übereinstimmt.
quelle
std::bind
, und beide tun wirklich dasselbe, außer dass Lambdas nicht in dem Sinne polymorph sind, dass sie unterschiedliche Argumenttypen akzeptieren können.binding
in meiner Liste) zu erstellen . Dies können Sie mit Funktionszeigern nicht erreichen.Ein Delegat ist eine Klasse, die einen Zeiger oder Verweis auf eine Objektinstanz umschließt, eine Mitgliedsmethode der Klasse dieses Objekts, die für diese Objektinstanz aufgerufen werden soll, und eine Methode zum Auslösen dieses Aufrufs bereitstellt.
Hier ist ein Beispiel:
quelle
Execute()
der der Funktionsaufruf für das Objekt ausgelöst wird, das der Delegate umschließt.Die Notwendigkeit von C ++ - Delegatenimplementierungen ist für die C ++ - Community eine dauerhafte Verlegenheit. Jeder C ++ - Programmierer würde sie gerne haben, also verwenden sie sie schließlich trotz der Tatsachen, dass:
std::function()
verwendet Heap-Operationen (und ist für ernsthafte eingebettete Programmierung unerreichbar).Alle anderen Implementierungen machen mehr oder weniger Zugeständnisse hinsichtlich der Portabilität oder Standardkonformität (überprüfen Sie dies bitte, indem Sie die verschiedenen Delegate-Implementierungen hier und im Codeprojekt überprüfen). Ich habe noch keine Implementierung gesehen, die keine wilden reinterpret_casts verwendet, verschachtelte Klassen- "Prototypen", die hoffentlich Funktionszeiger mit der gleichen Größe wie die vom Benutzer übergebenen erzeugen, Compiler-Tricks wie zuerst vorwärts deklarieren, dann typedef und dann erneut deklarieren. diesmal von einer anderen Klasse oder ähnlichen zwielichtigen Techniken erben. Während es eine großartige Leistung für die Implementierer ist, die das erstellt haben, ist es immer noch ein trauriges Zeugnis darüber, wie sich C ++ entwickelt.
Nur selten wird darauf hingewiesen, dass die Delegierten nun über 3 C ++ - Standardrevisionen nicht richtig angesprochen wurden. (Oder das Fehlen von Sprachfunktionen, die eine einfache Implementierung von Delegierten ermöglichen.)
Mit der Art und Weise, wie C ++ 11-Lambda-Funktionen durch den Standard definiert werden (jedes Lambda hat einen anonymen, unterschiedlichen Typ), hat sich die Situation nur in einigen Anwendungsfällen verbessert. Für den Anwendungsfall der Verwendung von Delegaten in (DLL-) Bibliotheks-APIs können Lambdas allein jedoch immer noch nicht verwendet werden. Die übliche Technik besteht darin, das Lambda zuerst in eine std :: -Funktion zu packen und es dann über die API zu übergeben.
quelle
std::function
nicht immer dynamisch zuordnenEin Delegat bietet ganz einfach Funktionen für die Funktionsweise eines Funktionszeigers. Es gibt viele Einschränkungen von Funktionszeigern in C ++. Ein Delegat verwendet eine Vorlage-Unangenehmkeit hinter den Kulissen, um ein Funktionszeiger-Element der Vorlagenklasse zu erstellen, das so funktioniert, wie Sie es möchten.
Das heißt, Sie können sie so einstellen, dass sie auf eine bestimmte Funktion zeigen, und Sie können sie weitergeben und aufrufen, wann und wo immer Sie möchten.
Hier gibt es einige sehr gute Beispiele:
quelle
Eine Option für Delegierte in C ++, die hier nicht anders erwähnt wird, besteht darin, den C-Stil mit einer Funktion ptr und einem Kontextargument auszuführen. Dies ist wahrscheinlich das gleiche Muster, das viele, die diese Frage stellen, zu vermeiden versuchen. Das Muster ist jedoch portabel, effizient und kann in eingebettetem Code und Kernel-Code verwendet werden.
quelle
Windows-Laufzeitäquivalent eines Funktionsobjekts in Standard-C ++. Man kann die gesamte Funktion als Parameter verwenden (eigentlich ist das ein Funktionszeiger). Es wird hauptsächlich in Verbindung mit Ereignissen verwendet. Der Delegierte repräsentiert einen Vertrag, den Event-Handler viel erfüllen. Es erleichtert, wie ein Funktionszeiger funktionieren kann.
quelle