Fungsi Panggilan Balik di C++

Callback Function C

Fungsi panggilan balik adalah fungsi, yang merupakan argumen, bukan parameter, dalam fungsi lain. Fungsi lainnya dapat disebut fungsi utama. Jadi dua fungsi terlibat: fungsi utama dan fungsi panggilan balik itu sendiri. Dalam daftar parameter fungsi utama, ada deklarasi fungsi panggilan balik tanpa definisinya, sama seperti deklarasi objek tanpa penetapan. Fungsi utama dipanggil dengan argumen (dalam main()). Salah satu argumen dalam panggilan fungsi utama adalah definisi efektif dari fungsi panggilan balik. Dalam C++, argumen ini adalah referensi ke definisi fungsi panggilan balik; itu bukan definisi sebenarnya. Fungsi panggilan balik itu sendiri sebenarnya dipanggil dalam definisi fungsi utama.

Fungsi panggilan balik dasar di C++ tidak menjamin perilaku asinkron dalam suatu program. Perilaku asinkron adalah manfaat nyata dari skema fungsi panggilan balik. Dalam skema fungsi panggilan balik asinkron, hasil fungsi utama harus diperoleh untuk program sebelum hasil fungsi panggilan balik diperoleh. Dimungkinkan untuk melakukan ini di C++; namun, C++ memiliki pustaka yang disebut masa depan untuk menjamin perilaku skema fungsi panggilan balik asinkron.



Artikel ini menjelaskan skema fungsi panggilan balik dasar. Banyak dari itu dengan C++ murni. Sejauh menyangkut panggilan balik, perilaku dasar perpustakaan masa depan juga dijelaskan. Pengetahuan dasar tentang C++ dan petunjuknya diperlukan untuk memahami artikel ini.



Isi Artikel

Skema Fungsi Panggilan Balik Dasar

Skema fungsi panggilan balik membutuhkan fungsi utama, dan fungsi panggilan balik itu sendiri. Deklarasi fungsi callback adalah bagian dari daftar parameter fungsi utama. Definisi fungsi panggilan balik ditunjukkan dalam panggilan fungsi dari fungsi utama. Fungsi panggilan balik sebenarnya dipanggil dalam definisi fungsi utama. Program berikut menggambarkan hal ini:



#termasuk

menggunakan ruang namajam;



ke dalammainFn(arangch[],ke dalam (*ptr)(ke dalam))

{

ke dalamid1= 1;

ke dalamid2= 2;

ke dalambiasanya= (*ptr)(id2);

biaya<<'fungsi utama:'<<id1<<''<<ch<<''<<biasanya<<' ';

kembaliid1;

}


ke dalamcb(ke dalamiden)

{

biaya<<'fungsi panggilan balik'<<' ';

kembaliiden;

}


ke dalamutama()

{

ke dalam (*ptr)(ke dalam) = &cb;

arangtidak[] = 'dan';

mainFn(ayah, cb);



kembali 0;

}

Outputnya adalah:

fungsi panggilan balik

fungsi utama: 1 dan 2

Fungsi utama diidentifikasi oleh principalFn(). Fungsi panggilan balik diidentifikasi oleh cb(). Fungsi panggilan balik didefinisikan di luar fungsi utama tetapi sebenarnya dipanggil di dalam fungsi utama.

Perhatikan deklarasi fungsi callback sebagai parameter dalam daftar parameter deklarasi fungsi utama. Deklarasi fungsi callback adalah int (*ptr)(int). Perhatikan ekspresi fungsi panggilan balik, seperti panggilan fungsi, dalam definisi fungsi utama; argumen apa pun untuk panggilan fungsi panggilan balik dilewatkan di sana. Pernyataan untuk pemanggilan fungsi ini adalah:



ke dalambiasanya= (*ptr)(id2);

Di mana id2 adalah argumen. ptr adalah bagian dari parameter, pointer, yang akan ditautkan ke referensi fungsi callback di fungsi main().

Perhatikan ungkapan:

ke dalam (*ptr)(ke dalam) = &cb;

Dalam fungsi main(), yang menautkan deklarasi (tanpa definisi) fungsi panggilan balik ke nama definisi fungsi panggilan balik yang sama.

Fungsi utama dipanggil, dalam fungsi main(), sebagai:

mainFn(ayah, cb);

Di mana cha adalah string dan cb adalah nama fungsi panggilan balik tanpa argumennya.

Perilaku Sinkron dari Fungsi Panggilan Balik

Perhatikan program berikut:

#termasuk

menggunakan ruang namajam;



ruang kosongmainFn(ruang kosong (*ptr)())

{

biaya<<'fungsi utama'<<' ';

(*ptr)();

}


ruang kosongcb()

{

biaya<<'fungsi panggilan balik'<<' ';

}


ruang kosongfn()

{

biaya<<'terlihat'<<' ';

}


ke dalamutama()

{

ruang kosong (*ptr)() = &cb;

mainFn(cb);

fn();



kembali 0;

}

Outputnya adalah:

fungsi utama

fungsi panggilan balik

terlihat

Ada fungsi baru di sini. Semua fungsi baru, adalah untuk menampilkan output, terlihat. Dalam fungsi main(), fungsi utama dipanggil, kemudian fungsi baru, fn() dipanggil. Outputnya menunjukkan bahwa kode untuk fungsi utama dieksekusi, kemudian untuk fungsi panggilan balik dieksekusi, dan terakhir untuk fungsi fn() dieksekusi. Ini adalah perilaku sinkron (berulir tunggal).

Jika itu adalah perilaku asinkron, ketika tiga segmen kode dipanggil secara berurutan, segmen kode pertama dapat dieksekusi, diikuti oleh eksekusi segmen kode ketiga, sebelum segmen kode kedua dieksekusi.

Nah, fungsi fn() dapat dipanggil dari dalam definisi fungsi utama, bukan dari dalam fungsi main(), sebagai berikut:

#termasuk

menggunakan ruang namajam;



ruang kosongfn()

{

biaya<<'terlihat'<<' ';

}


ruang kosongmainFn(ruang kosong (*ptr)())

{

biaya<<'fungsi utama'<<' ';

fn();

(*ptr)();

}


ruang kosongcb()

{

biaya<<'fungsi panggilan balik'<<' ';

}


ke dalamutama()

{

ruang kosong (*ptr)() = &cb;

mainFn(cb);



kembali 0;

}

Outputnya adalah:

fungsi utama

terlihat

fungsi panggilan balik

Ini adalah tiruan dari perilaku asinkron. Ini bukan perilaku asinkron. Itu masih perilaku sinkron.

Juga, urutan eksekusi segmen kode fungsi utama dan segmen kode fungsi panggilan balik dapat ditukar dalam definisi fungsi utama. Program berikut menggambarkan hal ini:

#termasuk

menggunakan ruang namajam;



ruang kosongmainFn(ruang kosong (*ptr)())

{

(*ptr)();

biaya<<'fungsi utama'<<' ';

}


ruang kosongcb()

{

biaya<<'fungsi panggilan balik'<<' ';

}


ruang kosongfn()

{

biaya<<'terlihat'<<' ';

}


ke dalamutama()

{

ruang kosong (*ptr)() = &cb;

mainFn(cb);

fn();



kembali 0;

}

Outputnya sekarang,

fungsi panggilan balik

fungsi utama

terlihat

Ini juga merupakan tiruan dari perilaku asinkron. Ini bukan perilaku asinkron. Itu masih perilaku sinkron. Perilaku asinkron yang sebenarnya dapat diperoleh seperti yang dijelaskan di bagian selanjutnya atau dengan perpustakaan, di masa mendatang.

Perilaku Asinkron dengan Fungsi Panggilan Balik

Kode semu untuk skema fungsi panggilan balik asinkron dasar adalah:

ketik keluaran;

ketik cb(ketik keluaran)

{

//pernyataan

}


ketik prinsipFn(ketik input, ketik cb(ketik keluaran))

{

//pernyataan

}

Perhatikan posisi data input dan output di tempat yang berbeda dari pseudo-code. Input dari fungsi callback adalah outputnya. Parameter dari fungsi utama adalah parameter input untuk kode umum dan parameter untuk fungsi callback. Dengan skema ini, fungsi ketiga dapat dieksekusi (dipanggil) di fungsi main() sebelum output dari fungsi callback dibaca (masih di fungsi main()). Kode berikut menggambarkan hal ini:

#termasuk

menggunakan ruang namajam;

arang *keluaran;


ruang kosongcb(arangkeluar[])

{

keluaran=keluar;

}



ruang kosongmainFn(arangmemasukkan[],ruang kosong (*ptr)(arang[lima puluh]))

{

(*ptr)(memasukkan);

biaya<<'fungsi utama'<<' ';

}


ruang kosongfn()

{

biaya<<'terlihat'<<' ';

}


ke dalamutama()

{

arangmemasukkan[] = 'fungsi panggilan balik';

ruang kosong (*ptr)(arang[]) = &cb;

mainFn(masukan, cb);

fn();

biaya<<keluaran<<' ';



kembali 0;

}

Keluaran programnya adalah:

fungsi utama

terlihat

fungsi panggilan balik

Dalam kode khusus ini, datum keluaran dan masukan kebetulan merupakan datum yang sama. Hasil dari pemanggilan fungsi ketiga dalam fungsi main() telah ditampilkan sebelum hasil dari fungsi pemanggilan balik. Fungsi panggilan balik dieksekusi, selesai, dan menetapkan hasilnya (nilai) ke variabel, output, memungkinkan program untuk melanjutkan tanpa gangguannya. Dalam fungsi main(), output dari fungsi callback digunakan (dibaca dan ditampilkan) saat dibutuhkan, yang mengarah ke perilaku asinkron untuk keseluruhan skema.

Ini adalah cara utas tunggal untuk mendapatkan perilaku asinkron fungsi panggilan balik dengan C++ murni.

Penggunaan dasar Perpustakaan masa depan

Gagasan skema fungsi panggilan balik asinkron adalah bahwa fungsi utama kembali sebelum fungsi panggilan balik kembali. Ini dilakukan secara tidak langsung, efektif, dalam kode di atas.

Perhatikan dari kode di atas bahwa fungsi callback menerima input utama untuk kode dan menghasilkan output utama untuk kode tersebut. Pustaka C++, di masa mendatang, memiliki fungsi yang disebut sync(). Argumen pertama untuk fungsi ini adalah referensi fungsi panggilan balik; argumen kedua adalah input ke fungsi panggilan balik. Fungsi sync() kembali tanpa menunggu eksekusi fungsi callback selesai tetapi memungkinkan fungsi callback selesai. Ini memberikan perilaku asinkron. Sementara fungsi callback terus dijalankan, karena fungsi sync() telah kembali, pernyataan di bawahnya terus dijalankan. Ini seperti perilaku asinkron yang ideal.

Program di atas telah ditulis ulang di bawah ini, dengan mempertimbangkan pustaka masa depan dan fungsi sync()-nya:

#termasuk

#termasuk

#termasuk

menggunakan ruang namajam;

masa depan<rangkaian>keluaran;

string cb(string stri)

{

kembalistri;

}



ruang kosongmainFn(masukan string)

{

keluaran=tidak sinkron(cb, masukan);

biaya<<'fungsi utama'<<' ';

}


ruang kosongfn()

{

biaya<<'terlihat'<<' ';

}


ke dalamutama()

{

masukan string=rangkaian('fungsi panggilan balik');

mainFn(memasukkan);

fn();

tali ret=keluaran.Dapatkan(); //menunggu panggilan balik untuk kembali jika perlu

biaya<<Baik<<' ';



kembali 0;

}

Fungsi sync() akhirnya menyimpan output dari fungsi callback ke objek yang akan datang. Output yang diharapkan dapat diperoleh dalam fungsi main(), menggunakan fungsi anggota get() dari objek masa depan.

Kesimpulan

Fungsi panggilan balik adalah fungsi, yang merupakan argumen, bukan parameter, dalam fungsi lain. Skema fungsi panggilan balik membutuhkan fungsi utama, dan fungsi panggilan balik itu sendiri. Deklarasi fungsi callback adalah bagian dari daftar parameter fungsi utama. Definisi fungsi callback ditunjukkan dalam pemanggilan fungsi dari fungsi utama (dalam main()). Fungsi panggilan balik sebenarnya dipanggil dalam definisi fungsi utama.

Skema fungsi panggilan balik belum tentu asinkron. Untuk memastikan bahwa skema fungsi panggilan balik tidak sinkron, buat input utama ke kode, input ke fungsi panggilan balik; buat output utama dari kode, output dari fungsi panggilan balik; menyimpan output dari fungsi callback dalam variabel atau struktur data. Dalam fungsi main(), setelah memanggil fungsi utama, jalankan pernyataan lain dari aplikasi. Ketika output dari fungsi callback diperlukan, dalam fungsi main(), gunakan (baca dan tampilkan) di sana dan kemudian.