Saya kesulitan melihat kegunaan pointer fungsi. Saya kira ini mungkin berguna dalam beberapa kasus (bagaimanapun juga mereka ada), tetapi saya tidak dapat memikirkan kasus di mana lebih baik atau tidak dapat dihindari untuk menggunakan penunjuk fungsi.
Bisakah Anda memberikan beberapa contoh penggunaan yang baik dari pointer fungsi (dalam C atau C ++)?
Jawaban:
Sebagian besar contoh bermuara pada callback : Anda memanggil fungsi yang
f()
meneruskan alamat fungsi laing()
, danf()
memanggilg()
beberapa tugas tertentu. Jika Anda mengirimkanf()
alamath()
sebagai gantinya, makaf()
akan menelepon kembalih()
sebagai gantinya.Pada dasarnya, ini adalah cara untuk melakukan parametrize pada suatu fungsi: Beberapa bagian dari perilakunya tidak di-hardcode
f()
, tetapi ke dalam fungsi callback. Penelepon dapatf()
berperilaku berbeda dengan meneruskan fungsi panggilan balik yang berbeda. Klasik berasalqsort()
dari pustaka standar C yang menggunakan kriteria pengurutan sebagai penunjuk ke fungsi perbandingan.Dalam C ++, ini sering dilakukan dengan menggunakan objek fungsi (juga disebut functors). Ini adalah objek yang membebani operator pemanggil fungsi, sehingga Anda dapat memanggilnya seolah-olah mereka adalah sebuah fungsi. Contoh:
Ide di balik ini adalah, tidak seperti penunjuk fungsi, objek fungsi tidak hanya dapat membawa algoritme, tetapi juga data:
Keuntungan lainnya adalah terkadang lebih mudah untuk panggilan sebaris ke objek fungsi daripada panggilan melalui pointer fungsi. Inilah alasan mengapa pengurutan di C ++ terkadang lebih cepat daripada pengurutan di C.
sumber
Yah, saya biasanya menggunakannya (secara profesional) dalam tabel lompat (lihat juga pertanyaan StackOverflow ini ).
Tabel lompat biasanya (tetapi tidak secara eksklusif) digunakan dalam mesin keadaan terbatas untuk membuatnya digerakkan oleh data. Alih-alih switch / case bersarang
Anda dapat membuat array 2d dari fungsi pointer dan hanya memanggil
handleEvent[state][event]
sumber
Contoh:
sumber
std::sort
'scomp
parameter sebagai StrategiContoh "klasik" untuk kegunaan penunjuk fungsi adalah
qsort()
fungsi pustaka C , yang mengimplementasikan Quick Sort. Agar menjadi universal untuk setiap dan semua struktur data yang mungkin dibuat oleh pengguna, diperlukan beberapa penunjuk kosong ke data yang dapat diurutkan dan penunjuk ke fungsi yang mengetahui cara membandingkan dua elemen dari struktur data ini. Hal ini memungkinkan kita untuk membuat fungsi pilihan untuk pekerjaan tersebut, dan bahkan memungkinkan untuk memilih fungsi perbandingan pada waktu berjalan, misalnya untuk mengurutkan naik atau turun.sumber
Setuju dengan semua hal di atas, ditambah .... Saat Anda memuat dll secara dinamis saat runtime, Anda memerlukan pointer fungsi untuk memanggil fungsi.
sumber
Saya akan melawan arus di sini.
Di C, pointer fungsi adalah satu-satunya cara untuk mengimplementasikan kustomisasi, karena tidak ada OO.
Dalam C ++, Anda dapat menggunakan salah satu penunjuk fungsi atau functor (objek fungsi) untuk hasil yang sama.
Functors memiliki sejumlah keunggulan dibandingkan raw function pointer, karena sifat objeknya, terutama:
operator()
lambda
danbind
)Saya pribadi lebih suka functors ke pointer fungsi (terlepas dari kode boilerplate), sebagian besar karena sintaks untuk pointer fungsi dapat dengan mudah menjadi berbulu (dari Tutorial Function Pointer ):
Satu-satunya saat saya pernah melihat pointer fungsi digunakan di mana functor tidak bisa berada di Boost.Spirit. Mereka benar-benar menyalahgunakan sintaks untuk meneruskan sejumlah parameter yang berubah-ubah sebagai satu parameter template.
Tapi karena template variadic dan lambda sudah dekat, saya tidak yakin kita akan menggunakan pointer fungsi dalam kode C ++ murni untuk waktu yang lama.
sumber
bind
ataufunction
Anda menggunakan pointer fungsi. Ini seperti mengatakan kami tidak menggunakan pointer di C ++ karena kami menggunakan pointer pintar. Bagaimanapun, saya rewel.Di C, penggunaan klasik adalah fungsi qsort , di mana parameter keempat adalah penunjuk ke fungsi yang digunakan untuk melakukan pengurutan dalam sort. Dalam C ++, seseorang akan cenderung menggunakan functors (objek yang terlihat seperti fungsi) untuk hal semacam ini.
sumber
Saya menggunakan pointer fungsi baru-baru ini untuk membuat lapisan abstraksi.
Saya memiliki program yang ditulis dalam C murni yang berjalan pada sistem tertanam. Ini mendukung beberapa varian perangkat keras. Bergantung pada perangkat keras yang saya gunakan, itu perlu memanggil versi berbeda dari beberapa fungsi.
Pada waktu inisialisasi, program mencari tahu perangkat keras apa yang dijalankannya dan mengisi penunjuk fungsi. Semua rutinitas tingkat tinggi dalam program hanya memanggil fungsi yang dirujuk oleh pointer. Saya dapat menambahkan dukungan untuk varian perangkat keras baru tanpa menyentuh rutinitas tingkat yang lebih tinggi.
Saya dulu menggunakan pernyataan switch / case untuk memilih versi fungsi yang tepat, tetapi ini menjadi tidak praktis karena program tersebut berkembang untuk mendukung lebih banyak varian perangkat keras. Saya harus menambahkan pernyataan kasus di semua tempat.
Saya juga mencoba lapisan fungsi menengah untuk mencari tahu fungsi mana yang akan digunakan, tetapi mereka tidak banyak membantu. Saya masih harus memperbarui pernyataan kasus di banyak tempat setiap kali kami menambahkan varian baru. Dengan fungsi pointer, saya hanya perlu mengubah fungsi inisialisasi.
sumber
Seperti yang dikatakan Rich di atas, biasanya pointer fungsi di Windows merujuk ke beberapa alamat yang menyimpan fungsi.
Saat Anda memprogram di
C language
platform Windows, pada dasarnya Anda memuat beberapa file DLL di memori utama (menggunakanLoadLibrary
) dan untuk menggunakan fungsi yang disimpan di DLL, Anda perlu membuat penunjuk fungsi dan menunjuk ke alamat ini (menggunakanGetProcAddress
).Referensi:
LoadLibrary
GetProcAddress
sumber
Pointer fungsi dapat digunakan di C untuk membuat antarmuka yang akan diprogram. Bergantung pada fungsionalitas spesifik yang diperlukan saat runtime, implementasi berbeda dapat ditetapkan ke penunjuk fungsi.
sumber
Penggunaan utama saya dari mereka adalah PANGGILAN: ketika Anda perlu menyimpan informasi tentang suatu fungsi untuk dipanggil nanti .
Katakanlah Anda sedang menulis Bomberman. 5 detik setelah orang tersebut menjatuhkan bom, bom tersebut akan meledak (panggil
explode()
fungsinya).Sekarang ada 2 cara untuk melakukannya. Salah satu caranya adalah dengan "menyelidiki" semua bom di layar untuk melihat apakah bom tersebut siap meledak di loop utama.
Cara lain adalah dengan memasang panggilan balik ke sistem jam Anda. Saat bom ditanam, Anda menambahkan callback untuk memanggil bomb.explode () jika waktunya tepat .
Di sini
callback.function()
bisa ada fungsi apa saja , karena ini adalah fungsi penunjuk.sumber
Penggunaan penunjuk fungsi
Untuk memanggil fungsi secara dinamis berdasarkan masukan pengguna. Dengan membuat peta string dan fungsi pointer dalam kasus ini.
Dengan cara ini kami telah menggunakan penunjuk fungsi dalam kode perusahaan kami yang sebenarnya. Anda dapat menulis nomor 'n' dari fungsi dan memanggilnya menggunakan metode ini.
KELUARAN:
sumber
Perspektif yang berbeda, selain jawaban bagus lainnya di sini:
Di C, Anda hanya menggunakan fungsi pointer, bukan fungsi (secara langsung).
Maksud saya, Anda menulis fungsi, tetapi Anda tidak dapat memanipulasi fungsi. Tidak ada representasi run-time dari suatu fungsi yang dapat Anda gunakan. Anda bahkan tidak bisa menyebut "fungsi". Saat Anda menulis:
apa yang sebenarnya Anda katakan adalah "melakukan panggilan ke
my_function
pointer dengan argumen yang ditentukan". Anda melakukan panggilan melalui penunjuk fungsi. Peluruhan ini menjadi penunjuk fungsi berarti bahwa perintah berikut ini setara dengan pemanggilan fungsi sebelumnya:dan seterusnya (terima kasih @LuuVinhPhuc).
Jadi, Anda sudah menggunakan pointer fungsi sebagai nilai . Jelas Anda ingin memiliki variabel untuk nilai-nilai itu - dan di sinilah semua penggunaan metion lain masuk: Polimorfisme / kustomisasi (seperti di qsort), callback, tabel lompat dll.
Dalam C ++ hal-hal menjadi sedikit lebih rumit, karena kita memiliki lambda, dan objek dengan
operator()
, dan bahkan sebuahstd::function
kelas, tetapi prinsipnya sebagian besar masih sama.sumber
(&my_function)(my_arg)
,(*my_function)(my_arg)
,(**my_function)(my_arg)
,(&**my_function)(my_arg)
,(***my_function)(my_arg)
... karena fungsi meluruh sampai pointer fungsiUntuk bahasa OO, untuk melakukan panggilan polimorfik di belakang layar (ini juga berlaku untuk C hingga titik tertentu, saya kira).
Selain itu, mereka sangat berguna untuk memasukkan perilaku yang berbeda ke fungsi lain (foo) saat runtime. Itu membuat fungsi menjadi fungsi tingkat tinggi. Selain fleksibilitasnya, yang membuat kode foo lebih mudah dibaca karena memungkinkan Anda menarik logika ekstra "if-else" darinya.
Ini memungkinkan banyak hal berguna lainnya dengan Python seperti generator, closure dll.
sumber
Saya menggunakan pointer fungsi secara ekstensif, untuk meniru mikroprosesor yang memiliki opcode 1-byte. Sebuah array dari 256 pointer fungsi adalah cara alami untuk mengimplementasikannya.
sumber
Satu penggunaan pointer fungsi bisa jadi di mana kita mungkin tidak ingin mengubah kode di mana fungsi dipanggil (artinya dengan demikian panggilan mungkin bersyarat dan dalam kondisi yang berbeda, kita perlu melakukan jenis pemrosesan yang berbeda). Di sini pointer fungsi sangat berguna, karena kita tidak perlu memodifikasi kode di tempat fungsi dipanggil. Kami cukup memanggil fungsi menggunakan penunjuk fungsi dengan argumen yang sesuai. Penunjuk fungsi dapat dibuat untuk menunjukkan fungsi yang berbeda secara kondisional. (Ini dapat dilakukan di suatu tempat selama fase inisialisasi). Selain itu, model di atas sangat membantu, jika kita tidak dalam posisi untuk mengubah kode di mana ia dipanggil (misalkan itu adalah API perpustakaan yang tidak dapat kita modifikasi). API menggunakan penunjuk fungsi untuk memanggil fungsi yang ditentukan pengguna yang sesuai.
sumber
Saya akan mencoba memberikan daftar yang agak lengkap di sini:
Callbacks : Sesuaikan beberapa fungsionalitas (pustaka) dengan kode yang diberikan pengguna. Contoh utamanya adalah
qsort()
, tetapi juga berguna untuk menangani peristiwa (seperti tombol yang memanggil callback saat diklik), atau diperlukan untuk memulai thread (pthread_create()
).Polimorfisme : vtabel di kelas C ++ tidak lain adalah tabel penunjuk fungsi. Dan program C juga dapat memilih untuk menyediakan vtable untuk beberapa objeknya:
Konstruktor dari
Derived
kemudian akan menetapkanvtable
variabel anggotanya ke objek global dengan implementasi kelas turunan daridestruct
danfrobnicate
, dan kode yang diperlukan untuk menghancurkan sebuahstruct Base*
panggilan akan cukupbase->vtable->destruct(base)
, yang akan memanggil versi destruktor yang benar, terlepas dari kelas turunan yangbase
sebenarnya menunjuk ke .Tanpa pointer fungsi, polimorfisme perlu dikodekan dengan sekumpulan konstruksi sakelar seperti
Ini menjadi agak berat dengan cepat.
Kode yang dimuat secara dinamis : Ketika sebuah program memuat modul ke dalam memori dan mencoba memanggil kodenya, program tersebut harus melalui penunjuk fungsi.
Semua penggunaan pointer fungsi yang pernah saya lihat termasuk dalam salah satu dari tiga kelas besar ini.
sumber