C++'da Geri Çağırma İşlevi

Callback Function C



Geri arama işlevi, başka bir işlevde parametre değil, bağımsız değişken olan bir işlevdir. Diğer fonksiyon asıl fonksiyon olarak adlandırılabilir. Dolayısıyla iki işlev söz konusudur: asıl işlev ve geri arama işlevinin kendisi. Ana işlevin parametre listesinde, atamasız nesne bildirimleri gibi, tanımı olmadan geri çağırma işlevinin bildirimi bulunur. Asıl işlev argümanlarla çağrılır (main() içinde). Asıl işlev çağrısındaki argümanlardan biri, geri arama işlevinin etkin tanımıdır. C++'da bu bağımsız değişken, geri arama işlevinin tanımına bir başvurudur; gerçek tanım değildir. Geri arama işlevinin kendisi aslında asıl işlevin tanımı içinde çağrılır.

C++'daki temel geri çağırma işlevi, bir programda zaman uyumsuz davranışı garanti etmez. Asenkron davranış, geri arama işlevi şemasının gerçek yararıdır. Asenkron geri çağırma işlevi şemasında, geri arama işlevinin sonucu elde edilmeden önce program için asıl işlevin sonucu alınmalıdır. Bunu C++'da yapmak mümkündür; ancak, C++, asenkron geri çağırma işlevi şemasının davranışını garanti etmek için future adlı bir kitaplığa sahiptir.







Bu makale, temel geri arama işlevi şemasını açıklar. Birçoğu saf C++ ile. Geri arama söz konusu olduğunda, gelecekteki kütüphanenin temel davranışı da açıklanmıştır. Bu makalenin anlaşılması için temel C++ ve işaretçileri bilgisi gereklidir.



Makale İçeriği

Temel Geri Çağırma İşlev Şeması

Bir geri arama işlevi şeması, bir ana işleve ve geri arama işlevinin kendisine ihtiyaç duyar. Geri arama işlevinin bildirimi, asıl işlevin parametre listesinin bir parçasıdır. Geri arama işlevinin tanımı, asıl işlevin işlev çağrısında belirtilir. Geri arama işlevi aslında asıl işlevin tanımı içinde çağrılır. Aşağıdaki program bunu göstermektedir:



#Dahil etmek

kullanarak ad alanısaat;



intanaFn(karakterch[],int (*ptr)(int))

{

intid1= 1;

intid2= 2;

intgenellikle= (*ptr)(id2);

maliyet<<'ana işlev:'<<id1<<''<<ch<<''<<genellikle<<' ';

dönüşid1;

}


intcb(intkimlik)

{

maliyet<<'geri arama işlevi'<<' ';

dönüşkimlik;

}


intana()

{

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

karakternumara[] = 've';

anaFn(baba, cb);



dönüş 0;

}

Çıktı:





geri arama işlevi

asıl işlev: 1 ve 2

Asıl işlev, PrincipalFn() ile tanımlanır. Geri arama işlevi cb() ile tanımlanır. Geri arama işlevi, asıl işlevin dışında tanımlanır, ancak aslında asıl işlev içinde çağrılır.

Ana işlev bildiriminin parametre listesinde bir parametre olarak geri çağırma işlevinin bildirimini not edin. Geri arama işlevinin bildirimi int (*ptr)(int) şeklindedir. Temel işlevin tanımındaki bir işlev çağrısı gibi geri arama işlevi ifadesini not edin; geri arama işlevi çağrısı için herhangi bir argüman oraya iletilir. Bu işlev çağrısının ifadesi:



intgenellikle= (*ptr)(id2);

id2'nin bir argüman olduğu yer. ptr, main() işlevindeki geri çağırma işlevinin referansına bağlanacak olan bir işaretçi olan parametrenin bir parçasıdır.

Şu ifadeye dikkat edin:

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

Geri arama işlevinin bildirimini (tanımsız) aynı geri arama işlevinin tanımının adına bağlayan main() işlevinde.

main() işlevinde ana işlev şu şekilde çağrılır:

anaFn(baba, cb);

Burada cha bir dizgedir ve cb, herhangi bir argümanı olmadan geri çağırma işlevinin adıdır.

Geri Çağırma İşlevinin Eşzamanlı Davranışı

Aşağıdaki programı göz önünde bulundurun:

#Dahil etmek

kullanarak ad alanısaat;



geçersizanaFn(geçersiz (*ptr)())

{

maliyet<<'ana işlev'<<' ';

(*ptr)();

}


geçersizcb()

{

maliyet<<'geri arama işlevi'<<' ';

}


geçersizfn()

{

maliyet<<'görülen'<<' ';

}


intana()

{

geçersiz (*ptr)() = &cb;

anaFn(cb);

fn();



dönüş 0;

}

Çıktı:

asıl işlev

geri arama işlevi

görülen

Burada yeni bir fonksiyon var. Tüm yeni işlev, görülen çıktıyı görüntülemektir. main() işlevinde, asıl işlev çağrılır, ardından yeni işlev olan fn() çağrılır. Çıktı, ana işlev kodunun yürütüldüğünü, ardından geri çağırma işlevi için kodun yürütüldüğünü ve son olarak fn() işlevi için kodun yürütüldüğünü gösterir. Bu, eşzamanlı (tek iş parçacıklı) davranıştır.

Eşzamansız davranış olsaydı, sırayla üç kod parçası çağrıldığında, birinci kod parçası yürütülebilir, ardından ikinci kod parçası yürütülmeden önce üçüncü kod parçası yürütülebilir.

Peki, fn() işlevi, main() işlevinin içinden değil, asıl işlevin tanımından aşağıdaki gibi çağrılabilir:

#Dahil etmek

kullanarak ad alanısaat;



geçersizfn()

{

maliyet<<'görülen'<<' ';

}


geçersizanaFn(geçersiz (*ptr)())

{

maliyet<<'ana işlev'<<' ';

fn();

(*ptr)();

}


geçersizcb()

{

maliyet<<'geri arama işlevi'<<' ';

}


intana()

{

geçersiz (*ptr)() = &cb;

anaFn(cb);



dönüş 0;

}

Çıktı:

asıl işlev

görülen

geri arama işlevi

Bu, eşzamansız davranışın bir taklididir. Asenkron davranış değildir. Hala senkronize davranıştır.

Ayrıca, ana işlevin kod bölümünün yürütme sırası ve geri arama işlevinin kod bölümü, ana işlevin tanımında yer değiştirebilir. Aşağıdaki program bunu göstermektedir:

#Dahil etmek

kullanarak ad alanısaat;



geçersizanaFn(geçersiz (*ptr)())

{

(*ptr)();

maliyet<<'ana işlev'<<' ';

}


geçersizcb()

{

maliyet<<'geri arama işlevi'<<' ';

}


geçersizfn()

{

maliyet<<'görülen'<<' ';

}


intana()

{

geçersiz (*ptr)() = &cb;

anaFn(cb);

fn();



dönüş 0;

}

Çıktı şimdi,

geri arama işlevi

asıl işlev

görülen

Bu aynı zamanda asenkron davranışın bir taklididir. Asenkron davranış değildir. Hala senkronize davranıştır. Gerçek asenkron davranış, bir sonraki bölümde veya gelecekte kütüphane ile açıklandığı gibi elde edilebilir.

Geri Çağırma İşlevli Eşzamansız Davranış

Temel eşzamansız geri arama işlevi şeması için sözde kod:

tip çıktı;

cb yazın(tip çıktı)

{

//ifadeler

}


tip anaFn(giriş yazın, cb yazın(tip çıktı))

{

//ifadeler

}

Sözde kodun farklı yerlerindeki giriş ve çıkış verilerinin konumlarını not edin. Geri arama işlevinin girişi, çıkışıdır. Ana işlevin parametreleri, genel kod için giriş parametresi ve geri arama işlevi için parametredir. Bu şema ile, geri arama işlevinin çıktısı okunmadan önce (hala main() işlevinde) main() işlevinde üçüncü bir işlev yürütülebilir (çağrılır). Aşağıdaki kod bunu göstermektedir:

#Dahil etmek

kullanarak ad alanısaat;

karakter *çıktı;


geçersizcb(karakterdışarı[])

{

çıktı=dışarı;

}



geçersizanaFn(karaktergiriş[],geçersiz (*ptr)(karakter[elli]))

{

(*ptr)(giriş);

maliyet<<'ana işlev'<<' ';

}


geçersizfn()

{

maliyet<<'görülen'<<' ';

}


intana()

{

karaktergiriş[] = 'geri arama işlevi';

geçersiz (*ptr)(karakter[]) = &cb;

anaFn(giriş, cb);

fn();

maliyet<<çıktı<<' ';



dönüş 0;

}

Programın çıktısı:

asıl işlev

görülen

geri arama işlevi

Bu özel kodda, çıktı ve girdi verisi aynı veri olur. main() işlevindeki üçüncü işlev çağrısının sonucu, geri arama işlevinin sonucundan önce görüntülendi. Geri çağırma işlevi yürütüldü, tamamlandı ve sonucunu (değerini) değişkene, çıktıya atadı ve programın müdahalesi olmadan devam etmesine izin verdi. main() işlevinde, gerektiğinde geri çağırma işlevinin çıktısı kullanıldı (okundu ve görüntülendi), tüm şema için eşzamansız davranışa yol açtı.

Bu, saf C++ ile geri çağırma işlevi zaman uyumsuz davranışı elde etmenin tek iş parçacıklı yoludur.

Gelecekteki Kitaplığın temel kullanımı

Eşzamansız geri arama işlevi şemasının fikri, asıl işlevin geri arama işlevi geri dönmeden önce dönmesidir. Bu, yukarıdaki kodda dolaylı olarak, etkili bir şekilde yapıldı.

Yukarıdaki koddan, geri arama işlevinin kod için ana girdiyi aldığını ve kod için ana çıktıyı ürettiğini unutmayın. Gelecekteki C++ kitaplığı, sync() adlı bir işleve sahiptir. Bu işlevin ilk argümanı geri arama işlevi başvurusudur; ikinci argüman, geri arama işlevinin girişidir. sync() işlevi, geri arama işlevinin yürütülmesinin tamamlanmasını beklemeden geri döner, ancak geri arama işlevinin tamamlanmasına izin verir. Bu, zaman uyumsuz davranış sağlar. Geri çağırma işlevi yürütülmeye devam ederken, sync() işlevi zaten döndüğünden, altındaki ifadeler yürütülmeye devam eder. Bu ideal asenkron davranış gibidir.

Yukarıdaki program, gelecekteki kitaplık ve sync() işlevi dikkate alınarak aşağıda yeniden yazılmıştır:

#Dahil etmek

#Dahil etmek

#Dahil etmek

kullanarak ad alanısaat;

gelecek<sicim>çıktı;

dize cb(dize şeridi)

{

dönüşçizgi;

}



geçersizanaFn(dize girişi)

{

çıktı=zaman uyumsuz(cb, giriş);

maliyet<<'ana işlev'<<' ';

}


geçersizfn()

{

maliyet<<'görülen'<<' ';

}


intana()

{

dize girişi=sicim('geri arama işlevi');

anaFn(giriş);

fn();

dize ret=çıktı.elde etmek(); //gerekirse geri aramanın dönmesini bekler

maliyet<<sağ<<' ';



dönüş 0;

}

sync() işlevi sonunda geri çağırma işlevinin çıktısını gelecekteki nesneye depolar. Beklenen çıktı, main() işlevinde, gelecekteki nesnenin get() üye işlevi kullanılarak elde edilebilir.

Çözüm

Geri arama işlevi, başka bir işlevde parametre değil, bağımsız değişken olan bir işlevdir. Bir geri arama işlevi şeması, bir ana işleve ve geri arama işlevinin kendisine ihtiyaç duyar. Geri arama işlevinin bildirimi, asıl işlevin parametre listesinin bir parçasıdır. Geri arama işlevinin tanımı, ana işlevin işlev çağrısında belirtilir (main() içinde). Geri arama işlevi aslında asıl işlevin tanımı içinde çağrılır.

Bir geri arama işlevi şeması mutlaka eşzamansız değildir. Geri arama fonksiyon şemasının asenkron olduğundan emin olmak için, kodun ana girişini, geri arama fonksiyonunun girişini yapın; kodun ana çıktısını, geri arama işlevinin çıktısını yapın; geri çağırma işlevinin çıktısını bir değişken veya veri yapısında saklayın. main() işlevinde, asıl işlevi çağırdıktan sonra, uygulamanın diğer deyimlerini yürütün. Geri arama işlevinin çıktısına ihtiyaç duyulduğunda, ana () işlevinde, onu orada ve sonra kullanın (okuyun ve görüntüleyin).