Callback-Funktion in C++

Callback Function C

Eine Callback-Funktion ist eine Funktion, die ein Argument und kein Parameter in einer anderen Funktion ist. Die andere Funktion kann als Hauptfunktion bezeichnet werden. Es sind also zwei Funktionen beteiligt: ​​die Principal-Funktion und die Callback-Funktion selbst. In der Parameterliste der Principal-Funktion steht die Deklaration der Callback-Funktion ohne deren Definition ebenso wie Objektdeklarationen ohne Zuweisung. Die Principal-Funktion wird mit Argumenten aufgerufen (in main()). Eines der Argumente im Hauptfunktionsaufruf ist die effektive Definition der Rückruffunktion. In C++ ist dieses Argument ein Verweis auf die Definition der Callback-Funktion; es ist nicht die eigentliche Definition. Die Callback-Funktion selbst wird tatsächlich innerhalb der Definition der Principal-Funktion aufgerufen.

Die grundlegende Callback-Funktion in C++ garantiert kein asynchrones Verhalten in einem Programm. Asynchrones Verhalten ist der wahre Vorteil des Callback-Funktionsschemas. Beim asynchronen Callback-Funktionsschema sollte das Ergebnis der Prinzipalfunktion für das Programm abgerufen werden, bevor das Ergebnis der Callback-Funktion abgerufen wird. Dies ist in C++ möglich; C++ verfügt jedoch über eine Bibliothek namens future, um das Verhalten des asynchronen Callback-Funktionsschemas zu gewährleisten.



In diesem Artikel wird das grundlegende Callback-Funktionsschema erläutert. Vieles davon mit reinem C++. Was den Callback betrifft, wird auch das grundsätzliche Verhalten der zukünftigen Bibliothek erklärt. Zum Verständnis dieses Artikels sind Grundkenntnisse in C++ und seinen Zeigern erforderlich.



Artikelinhalt

Grundlegendes Schema der Rückruffunktion

Ein Callback-Funktionsschema benötigt eine Principal-Funktion und die Callback-Funktion selbst. Die Deklaration der Callback-Funktion ist Teil der Parameterliste der Principal-Funktion. Die Definition der Callback-Funktion wird im Funktionsaufruf der Principal-Funktion angegeben. Die Callback-Funktion wird tatsächlich innerhalb der Definition der Principal-Funktion aufgerufen. Das folgende Programm veranschaulicht dies:



#enthalten

mit Namensraumstd;



intmainFn(verkohlenCH[],int (*ptr)(int))

{

intid1= 1;

intid2= 2;

intidr= (*ptr)(id2);

Kosten<<'Hauptfunktion: '<<id1<<''<<CH<<''<<idr<<' ';

Rückkehrid1;

}


intcb(intident)

{

Kosten<<'Rückruffunktion'<<' ';

Rückkehrident;

}


inthauptsächlich()

{

int (*ptr)(int) = &cb;

verkohlenNein[] = 'und';

mainFn(Vater, cb);



Rückkehr 0;

}

Die Ausgabe ist:

Rückruffunktion

Hauptfunktion: 1 und 2

Die Principal-Funktion wird durch PrincipalFn() identifiziert. Die Callback-Funktion wird durch cb() identifiziert. Die Callback-Funktion wird außerhalb der Principal-Funktion definiert, aber tatsächlich innerhalb der Principal-Funktion aufgerufen.

Beachten Sie die Deklaration der Callback-Funktion als Parameter in der Parameterliste der Deklaration der Principal-Funktion. Die Deklaration der Callback-Funktion ist int (*ptr)(int). Beachten Sie den Callback-Funktionsausdruck wie einen Funktionsaufruf in der Definition der Prinzipalfunktion; jedes Argument für den Callback-Funktionsaufruf wird dort übergeben. Die Anweisung für diesen Funktionsaufruf lautet:



intidr= (*ptr)(id2);

Wobei id2 ein Argument ist. ptr ist Teil des Parameters, ein Zeiger, der mit der Referenz der Callback-Funktion in der main()-Funktion verknüpft wird.

Beachten Sie den Ausdruck:

int (*ptr)(int) = &cb;

In der Funktion main(), die die Deklaration (ohne Definition) der Callback-Funktion mit dem Namen der Definition derselben Callback-Funktion verknüpft.

Die Hauptfunktion wird in der Funktion main() wie folgt aufgerufen:

mainFn(Vater, cb);

Dabei ist cha ein String und cb der Name der Callback-Funktion ohne deren Argumente.

Synchrones Verhalten der Callback-Funktion

Betrachten Sie das folgende Programm:

#enthalten

mit Namensraumstd;



LeeremainFn(Leere (*ptr)())

{

Kosten<<'Hauptfunktion'<<' ';

(*ptr)();

}


Leerecb()

{

Kosten<<'Rückruffunktion'<<' ';

}


Leerefn()

{

Kosten<<'gesehen'<<' ';

}


inthauptsächlich()

{

Leere (*ptr)() = &cb;

mainFn(cb);

fn();



Rückkehr 0;

}

Die Ausgabe ist:

Hauptfunktion

Rückruffunktion

gesehen

Hier gibt es eine neue Funktion. Alles, was die neue Funktion tut, ist, die Ausgabe anzuzeigen, gesehen. In der Funktion main() wird die Hauptfunktion aufgerufen, dann wird die neue Funktion fn() aufgerufen. Die Ausgabe zeigt, dass der Code für die Principal-Funktion ausgeführt wurde, dann der für die Callback-Funktion und schließlich der für die fn()-Funktion. Dies ist synchrones (Single-Thread-) Verhalten.

Wenn es sich um ein asynchrones Verhalten handelt, kann, wenn drei Codesegmente der Reihe nach aufgerufen werden, das erste Codesegment ausgeführt werden, gefolgt von der Ausführung des dritten Codesegments, bevor das zweite Codesegment ausgeführt wird.

Nun, die Funktion fn() kann aus der Definition der Hauptfunktion heraus aufgerufen werden, anstatt aus der main()-Funktion heraus, wie folgt:

#enthalten

mit Namensraumstd;



Leerefn()

{

Kosten<<'gesehen'<<' ';

}


LeeremainFn(Leere (*ptr)())

{

Kosten<<'Hauptfunktion'<<' ';

fn();

(*ptr)();

}


Leerecb()

{

Kosten<<'Rückruffunktion'<<' ';

}


inthauptsächlich()

{

Leere (*ptr)() = &cb;

mainFn(cb);



Rückkehr 0;

}

Die Ausgabe ist:

Hauptfunktion

gesehen

Rückruffunktion

Dies ist eine Imitation von asynchronem Verhalten. Es ist kein asynchrones Verhalten. Es ist immer noch synchrones Verhalten.

Außerdem kann die Ausführungsreihenfolge des Codesegments der Hauptfunktion und des Codesegments der Callback-Funktion in der Definition der Hauptfunktion vertauscht werden. Das folgende Programm veranschaulicht dies:

#enthalten

mit Namensraumstd;



LeeremainFn(Leere (*ptr)())

{

(*ptr)();

Kosten<<'Hauptfunktion'<<' ';

}


Leerecb()

{

Kosten<<'Rückruffunktion'<<' ';

}


Leerefn()

{

Kosten<<'gesehen'<<' ';

}


inthauptsächlich()

{

Leere (*ptr)() = &cb;

mainFn(cb);

fn();



Rückkehr 0;

}

Die Ausgabe ist jetzt,

Rückruffunktion

Hauptfunktion

gesehen

Dies ist auch eine Imitation von asynchronem Verhalten. Es ist kein asynchrones Verhalten. Es ist immer noch synchrones Verhalten. Echtes asynchrones Verhalten kann wie im nächsten Abschnitt erläutert oder mit der Bibliothek in Zukunft erreicht werden.

Asynchrones Verhalten mit Callback-Funktion

Der Pseudocode für das grundlegende asynchrone Callback-Funktionsschema lautet:

Typ Ausgabe;

Typ cb(Typ Ausgabe)

{

//Aussagen

}


Typ PrincipalFn(Typ Eingabe, Typ cb(Typ Ausgabe))

{

//Aussagen

}

Beachten Sie die Positionen der Eingabe- und Ausgabedaten an den verschiedenen Stellen des Pseudocodes. Die Eingabe der Callback-Funktion ist ihre Ausgabe. Die Parameter der Principal-Funktion sind der Eingabeparameter für den allgemeinen Code und der Parameter für die Callback-Funktion. Mit diesem Schema kann eine dritte Funktion in der main()-Funktion ausgeführt (aufgerufen) werden, bevor die Ausgabe der Callback-Funktion gelesen wird (noch in der main()-Funktion). Der folgende Code veranschaulicht dies:

#enthalten

mit Namensraumstd;

verkohlen *Ausgang;


Leerecb(verkohlenaus[])

{

Ausgang=aus;

}



LeeremainFn(verkohlenEingang[],Leere (*ptr)(verkohlen[fünfzig]))

{

(*ptr)(Eingang);

Kosten<<'Hauptfunktion'<<' ';

}


Leerefn()

{

Kosten<<'gesehen'<<' ';

}


inthauptsächlich()

{

verkohlenEingang[] = 'Rückruffunktion';

Leere (*ptr)(verkohlen[]) = &cb;

mainFn(Eingang, cb);

fn();

Kosten<<Ausgang<<' ';



Rückkehr 0;

}

Die Programmausgabe ist:

Hauptfunktion

gesehen

Rückruffunktion

In diesem speziellen Code sind das Ausgabe- und das Eingabedatum zufällig das gleiche Datum. Das Ergebnis des dritten Funktionsaufrufs in der main()-Funktion wurde vor dem Ergebnis der Callback-Funktion angezeigt. Die Callback-Funktion wurde ausgeführt, beendet und ihr Ergebnis (Wert) der Variablenausgabe zugewiesen, sodass das Programm ohne Einmischung fortgesetzt werden kann. In der main()-Funktion wurde die Ausgabe der Callback-Funktion verwendet (gelesen und angezeigt), wenn sie benötigt wurde, was zu einem asynchronen Verhalten für das gesamte Schema führte.

Dies ist die Singlethread-Methode, um mit reinem C++ asynchrones Verhalten der Callback-Funktion zu erhalten.

Grundlegende Nutzung der zukünftigen Bibliothek

Die Idee des asynchronen Callback-Funktionsschemas besteht darin, dass die Principal-Funktion zurückkehrt, bevor die Callback-Funktion zurückkehrt. Dies wurde im obigen Code indirekt und effektiv durchgeführt.

Beachten Sie im obigen Code, dass die Callback-Funktion die Haupteingabe für den Code empfängt und die Hauptausgabe für den Code erzeugt. Die C++-Bibliothek future hat eine Funktion namens sync(). Das erste Argument dieser Funktion ist die Callback-Funktionsreferenz; Das zweite Argument ist die Eingabe für die Callback-Funktion. Die Funktion sync() kehrt zurück, ohne auf den Abschluss der Ausführung der Callback-Funktion zu warten, lässt jedoch zu, dass die Callback-Funktion abgeschlossen wird. Dies bietet asynchrones Verhalten. Während die Callback-Funktion weiter ausgeführt wird, werden die Anweisungen darunter weiter ausgeführt, da die Funktion sync() bereits zurückgegeben hat. Dies ist wie ein ideales asynchrones Verhalten.

Das obige Programm wurde im Folgenden unter Berücksichtigung der zukünftigen Bibliothek und ihrer sync()-Funktion neu geschrieben:

#enthalten

#enthalten

#enthalten

mit Namensraumstd;

Zukunft<Schnur>Ausgang;

Saite cb(Streicher)

{

Rückkehrstr;

}



LeeremainFn(String-Eingabe)

{

Ausgang=asynchron(cb, Eingang);

Kosten<<'Hauptfunktion'<<' ';

}


Leerefn()

{

Kosten<<'gesehen'<<' ';

}


inthauptsächlich()

{

String-Eingabe=Schnur('Rückruffunktion');

mainFn(Eingang);

fn();

Zeichenfolge=Ausgang.werden(); // wartet, bis der Callback zurückkehrt, wenn nötig

Kosten<<rechts<<' ';



Rückkehr 0;

}

Die Funktion sync() speichert schließlich die Ausgabe der Callback-Funktion im Future-Objekt. Die erwartete Ausgabe kann in der main()-Funktion mithilfe der get()-Memberfunktion des Future-Objekts abgerufen werden.

Abschluss

Eine Callback-Funktion ist eine Funktion, die ein Argument und kein Parameter in einer anderen Funktion ist. Ein Callback-Funktionsschema benötigt eine Principal-Funktion und die Callback-Funktion selbst. Die Deklaration der Callback-Funktion ist Teil der Parameterliste der Principal-Funktion. Die Definition der Callback-Funktion wird im Funktionsaufruf der Principal-Funktion (in main()) angegeben. Die Callback-Funktion wird tatsächlich innerhalb der Definition der Principal-Funktion aufgerufen.

Ein Callback-Funktionsschema ist nicht unbedingt asynchron. Um sicherzustellen, dass das Callback-Funktionsschema asynchron ist, machen Sie die Haupteingabe für den Code, die Eingabe für die Callback-Funktion; machen Sie die Hauptausgabe des Codes, die Ausgabe der Rückruffunktion; Speichern Sie die Ausgabe der Callback-Funktion in einer Variablen oder Datenstruktur. Führen Sie in der main()-Funktion nach dem Aufrufen der Principal-Funktion andere Anweisungen der Anwendung aus. Wenn die Ausgabe der Callback-Funktion benötigt wird, verwenden Sie sie in der main()-Funktion (lesen und anzeigen) an Ort und Stelle.