Funkce zpětného volání v C ++

Callback Function C



Funkce zpětného volání je funkce, což je argument, nikoli parametr, v jiné funkci. Druhou funkci lze nazvat hlavní funkcí. Jedná se tedy o dvě funkce: hlavní funkci a samotnou funkci zpětného volání. V seznamu parametrů hlavní funkce je k dispozici deklarace funkce zpětného volání bez její definice, stejně jako jsou k dispozici deklarace objektů bez přiřazení. Hlavní funkce se nazývá s argumenty (v main ()). Jedním z argumentů ve volání hlavní funkce je efektivní definice funkce zpětného volání. V C ++ je tento argument odkazem na definici funkce zpětného volání; není to skutečná definice. Samotná funkce zpětného volání se ve skutečnosti nazývá v rámci definice hlavní funkce.

Základní funkce zpětného volání v C ++ nezaručuje asynchronní chování v programu. Asynchronní chování je skutečným přínosem schématu funkce zpětného volání. Ve schématu funkce asynchronního zpětného volání by měl být pro program získán výsledek hlavní funkce před získáním výsledku funkce zpětného volání. Je možné to provést v C ++; nicméně C ++ má knihovnu s názvem future, která zaručuje chování schématu funkce asynchronního zpětného volání.







Tento článek vysvětluje základní schéma funkce zpětného volání. Hodně z toho je s čistým C ++. Pokud jde o zpětné volání, je také vysvětleno základní chování budoucí knihovny. Základní znalosti C ++ a jeho ukazatelů jsou nezbytné pro pochopení tohoto článku.



Obsah článku

Základní schéma funkce zpětného volání

Schéma funkce zpětného volání potřebuje hlavní funkci a samotnou funkci zpětného volání. Deklarace funkce zpětného volání je součástí seznamu parametrů hlavní funkce. Definice funkce zpětného volání je uvedena ve volání funkce hlavní funkce. Funkce zpětného volání se ve skutečnosti volá v rámci definice hlavní funkce. Následující program to ilustruje:



#zahrnout

použitím jmenný prostorhodiny;



inthlavníFn(charch[],int (*ptr)(int))

{

intid1= 1;

intid2= 2;

intobvykle= (*ptr)(id2);

náklady<<'hlavní funkce:'<<id1<<''<<ch<<''<<obvykle<<' n';

vrátit seid1;

}


intcb(intiden)

{

náklady<<'funkce zpětného volání'<<' n';

vrátit seiden;

}


inthlavní()

{

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

charNe[] = 'a';

hlavníFn(otec, cb);



vrátit se 0;

}

Výstupem je:





funkce zpětného volání

hlavní funkce: 1 a 2

Hlavní funkce je identifikována principálemFn (). Funkce zpětného volání je označena cb (). Funkce zpětného volání je definována mimo hlavní funkci, ale ve skutečnosti se volá v rámci hlavní funkce.

Všimněte si deklarace funkce zpětného volání jako parametru v seznamu parametrů deklarace hlavní funkce. Deklarace funkce zpětného volání je int (*ptr) (int). Všimněte si výrazu funkce zpětného volání, jako je volání funkce, v definici hlavní funkce; je tam předán jakýkoli argument pro volání funkce zpětného volání. Příkaz pro toto volání funkce je:



intobvykle= (*ptr)(id2);

Kde id2 je argument. ptr je součástí parametru, ukazatele, který bude spojen s referencí funkce zpětného volání ve funkci main ().

Všimněte si výrazu:

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

Ve funkci main (), která propojuje deklaraci (bez definice) funkce zpětného volání s názvem definice stejné funkce zpětného volání.

Hlavní funkce se ve funkci main () nazývá jako:

hlavníFn(otec, cb);

Kde cha je řetězec a cb je název funkce zpětného volání bez jakéhokoli jejího argumentu.

Synchronní chování funkce zpětného volání

Zvažte následující program:

#zahrnout

použitím jmenný prostorhodiny;



prázdnéhlavníFn(prázdné (*ptr)())

{

náklady<<'hlavní funkce'<<' n';

(*ptr)();

}


prázdnécb()

{

náklady<<'funkce zpětného volání'<<' n';

}


prázdnéfn()

{

náklady<<'viděn'<<' n';

}


inthlavní()

{

prázdné (*ptr)() = &cb;

hlavníFn(cb);

fn();



vrátit se 0;

}

Výstupem je:

hlavní funkce

funkce zpětného volání

vidět

Je tu nová funkce. Vše, co nová funkce dělá, je zobrazit výstup, který vidíte. Ve funkci main () se nazývá hlavní funkce, poté se volá nová funkce, fn (). Výstup ukazuje, že byl spuštěn kód pro hlavní funkci, poté pro funkci zpětného volání a nakonec pro funkci fn (). Toto je synchronní chování (s jedním vláknem).

Pokud by se jednalo o asynchronní chování, když jsou tři kódové segmenty volány v pořadí, může být spuštěn první segment kódu, následovaný provedením třetího segmentu kódu, než bude spuštěn druhý segment kódu.

Funkci fn () lze volat z definice hlavní funkce, nikoli z funkce main (), a to následovně:

#zahrnout

použitím jmenný prostorhodiny;



prázdnéfn()

{

náklady<<'viděn'<<' n';

}


prázdnéhlavníFn(prázdné (*ptr)())

{

náklady<<'hlavní funkce'<<' n';

fn();

(*ptr)();

}


prázdnécb()

{

náklady<<'funkce zpětného volání'<<' n';

}


inthlavní()

{

prázdné (*ptr)() = &cb;

hlavníFn(cb);



vrátit se 0;

}

Výstupem je:

hlavní funkce

vidět

funkce zpětného volání

Toto je imitace asynchronního chování. Není to asynchronní chování. Je to stále synchronní chování.

V definici hlavní funkce lze také prohodit pořadí provedení segmentu kódu hlavní funkce a segmentu kódu funkce zpětného volání. Následující program to ilustruje:

#zahrnout

použitím jmenný prostorhodiny;



prázdnéhlavníFn(prázdné (*ptr)())

{

(*ptr)();

náklady<<'hlavní funkce'<<' n';

}


prázdnécb()

{

náklady<<'funkce zpětného volání'<<' n';

}


prázdnéfn()

{

náklady<<'viděn'<<' n';

}


inthlavní()

{

prázdné (*ptr)() = &cb;

hlavníFn(cb);

fn();



vrátit se 0;

}

Výstup je nyní,

funkce zpětného volání

hlavní funkce

vidět

Toto je také imitace asynchronního chování. Není to asynchronní chování. Je to stále synchronní chování. Skutečné asynchronní chování lze získat, jak je vysvětleno v další části nebo s knihovnou, budoucnost.

Asynchronní chování s funkcí zpětného volání

Pseudokód pro základní schéma funkce asynchronního zpětného volání je:

typový výstup;

zadejte cb(typový výstup)

{

// prohlášení

}


zadejte principalFn(zadejte vstup, zadejte cb(typový výstup))

{

// prohlášení

}

Poznamenejte si pozice vstupních a výstupních dat na různých místech pseudokódu. Vstupem funkce zpětného volání je jeho výstup. Parametry hlavní funkce jsou vstupním parametrem pro obecný kód a parametrem pro funkci zpětného volání. S tímto schématem lze provést (volat) třetí funkci ve funkci main () před načtením výstupu funkce zpětného volání (stále ve funkci main ()). Následující kód to ilustruje:

#zahrnout

použitím jmenný prostorhodiny;

char *výstup;


prázdnécb(charven[])

{

výstup=ven;

}



prázdnéhlavníFn(charvstup[],prázdné (*ptr)(char[padesátka]))

{

(*ptr)(vstup);

náklady<<'hlavní funkce'<<' n';

}


prázdnéfn()

{

náklady<<'viděn'<<' n';

}


inthlavní()

{

charvstup[] = 'funkce zpětného volání';

prázdné (*ptr)(char[]) = &cb;

hlavníFn(vstup, cb);

fn();

náklady<<výstup<<' n';



vrátit se 0;

}

Výstupem programu je:

hlavní funkce

vidět

funkce zpětného volání

V tomto konkrétním kódu je výstupní a vstupní nulový bod stejný. Výsledek třetího volání funkce ve funkci main () byl zobrazen před výsledkem funkce zpětného volání. Funkce zpětného volání byla spuštěna, dokončena a přiřazena svůj výsledek (hodnotu) proměnné, výstup, což umožňuje programu pokračovat bez jeho rušení. Ve funkci main () byl výstup funkce zpětného volání použit (přečten a zobrazen), když byl potřeba, což vedlo k asynchronnímu chování celého schématu.

Toto je způsob s jedním vláknem, jak získat asynchronní chování funkce zpětného volání s čistým C ++.

Základní využití budoucí knihovny

Myšlenka schématu funkce asynchronního zpětného volání spočívá v tom, že se hlavní funkce vrátí dříve, než se vrátí funkce zpětného volání. To bylo provedeno nepřímo, efektivně, ve výše uvedeném kódu.

Všimněte si výše uvedeného kódu, že funkce zpětného volání přijímá hlavní vstup pro kód a vytváří hlavní výstup pro kód. Knihovna C ++, budoucnost, má funkci nazvanou sync (). Prvním argumentem této funkce je odkaz na funkci zpětného volání; druhým argumentem je vstup do funkce zpětného volání. Funkce sync () se vrací bez čekání na dokončení funkce zpětného volání, ale umožňuje dokončení funkce zpětného volání. To poskytuje asynchronní chování. Zatímco funkce zpětného volání se nadále provádí, protože funkce sync () se již vrátila, příkazy pod ní se nadále provádějí. To je jako ideální asynchronní chování.

Výše uvedený program byl přepsán níže, s přihlédnutím k budoucí knihovně a její funkci sync ():

#zahrnout

#zahrnout

#zahrnout

použitím jmenný prostorhodiny;

budoucnost<tětiva>výstup;

řetězec cb(řetězec stri)

{

vrátit sestri;

}



prázdnéhlavníFn(řetězcový vstup)

{

výstup=asynchronní(cb, vstup);

náklady<<'hlavní funkce'<<' n';

}


prázdnéfn()

{

náklady<<'viděn'<<' n';

}


inthlavní()

{

řetězcový vstup=tětiva('funkce zpětného volání');

hlavníFn(vstup);

fn();

řetězec ret=výstup.dostat(); // čeká na návrat zpětného volání v případě potřeby

náklady<<že jo<<' n';



vrátit se 0;

}

Funkce sync () nakonec ukládá výstup funkce zpětného volání do budoucího objektu. Očekávaný výstup lze získat ve funkci main () pomocí členské funkce get () budoucího objektu.

Závěr

Funkce zpětného volání je funkce, což je argument, nikoli parametr, v jiné funkci. Schéma funkce zpětného volání potřebuje hlavní funkci a samotnou funkci zpětného volání. Deklarace funkce zpětného volání je součástí seznamu parametrů hlavní funkce. Definice funkce zpětného volání je uvedena ve volání funkce hlavní funkce (v main ()). Funkce zpětného volání se ve skutečnosti volá v rámci definice hlavní funkce.

Schéma funkce zpětného volání není nutně asynchronní. Chcete -li si být jisti, že schéma funkce zpětného volání je asynchronní, proveďte hlavní vstup do kódu, vstup do funkce zpětného volání; vytvořit hlavní výstup kódu, výstup funkce zpětného volání; uložit výstup funkce zpětného volání do proměnné nebo datové struktury. Ve funkci main () po volání hlavní funkce spusťte další příkazy aplikace. Když je potřeba výstup funkce zpětného volání, ve funkci main () ji použijte (přečtěte a zobrazte) tam a poté.