Bagaimana cara mendapatkan penunjuk fungsi untuk fungsi anggota kelas, dan kemudian memanggil fungsi anggota tersebut dengan objek tertentu? Saya ingin menulis:
class Dog : Animal
{
Dog ();
void bark ();
}
…
Dog* pDog = new Dog ();
BarkFunction pBark = &Dog::bark;
(*pBark) (pDog);
…
Juga, jika memungkinkan, saya juga ingin memanggil konstruktor melalui pointer:
NewAnimalFunction pNew = &Dog::Dog;
Animal* pAnimal = (*pNew)();
Apakah ini mungkin, dan jika demikian, cara apa yang lebih disukai untuk melakukan ini?
c++
function-pointers
class-method
Tony the Pony
sumber
sumber
Dog dog;
) kemungkinan besar adalah yang Anda inginkan.Jawaban:
Baca ini untuk detailnya:
sumber
*this.*pt2Member
akan berhasil.*
memiliki prioritas yang lebih tinggi daripada.*
... Secara pribadi, saya masih akan menulisthis->*pt2Member
, itu satu operator lebih sedikit.pt2ConstMember
keNULL
?(object.*method_pointer)
, jadi kami ingin*
memiliki prioritas yang lebih besar.this
hanya digunakan untuk menunjukkan bahwa apa pun yang Anda terapkan.*
harus menjadi penunjuk ke instance dari (sub) kelas. Namun ini adalah sintaks baru bagi saya, saya hanya menebak berdasarkan jawaban dan sumber daya lain yang ditautkan di sini. Saya menyarankan pengeditan untuk membuatnya lebih jelas.Paling mudah untuk memulai dengan a
typedef
. Untuk fungsi anggota, Anda menambahkan nama kelas di deklarasi type:Kemudian untuk memanggil metode tersebut, Anda menggunakan
->*
operator:Saya tidak percaya Anda dapat bekerja dengan konstruktor seperti ini - pemberi dan penjual itu istimewa. Cara normal untuk mencapai hal semacam itu akan menggunakan metode pabrik, yang pada dasarnya hanyalah fungsi statis yang memanggil konstruktor untuk Anda. Lihat kode di bawah ini sebagai contoh.
Saya telah memodifikasi kode Anda untuk melakukan apa yang pada dasarnya Anda gambarkan. Ada beberapa peringatan di bawah.
Sekarang meskipun Anda biasanya dapat menggunakan a
Dog*
sebagai penggantiAnimal*
berkat keajaiban polimorfisme, jenis penunjuk fungsi tidak mengikuti aturan pencarian hierarki kelas. Jadi penunjuk metode Hewan tidak kompatibel dengan penunjuk metode Anjing, dengan kata lain Anda tidak dapat menetapkan aDog* (*)()
ke variabel tipeAnimal* (*)()
.newDog
Metode statis adalah contoh sederhana dari sebuah pabrik, yang hanya membuat dan mengembalikan instance baru. Menjadi fungsi statis, ia memiliki regulertypedef
(tanpa kualifikasi kelas).Setelah menjawab pertanyaan di atas, saya bertanya-tanya apakah tidak ada cara yang lebih baik untuk mencapai apa yang Anda butuhkan. Ada beberapa skenario khusus di mana Anda akan melakukan hal semacam ini, tetapi Anda mungkin menemukan ada pola lain yang bekerja lebih baik untuk masalah Anda. Jika Anda mendeskripsikan dalam istilah yang lebih umum apa yang ingin Anda capai, pikiran sarang mungkin terbukti lebih berguna!
Terkait dengan hal di atas, Anda pasti akan menemukan pustaka Boost bind dan modul terkait lainnya sangat berguna.
sumber
->*
sebelumnya, tetapi sekarang saya harap saya tidak akan pernah membutuhkannya :)Saya tidak berpikir ada orang yang menjelaskan di sini bahwa satu masalah adalah Anda memerlukan " pointer anggota " daripada pointer fungsi normal.
Pointer anggota ke fungsi bukan sekadar pointer fungsi. Dalam istilah implementasi, kompilator tidak dapat menggunakan alamat fungsi sederhana karena, secara umum, Anda tidak tahu alamat yang akan dipanggil sampai Anda mengetahui objek mana yang akan didereferensi (pikirkan fungsi virtual). Anda juga perlu mengetahui objeknya untuk memberikan
this
parameter implisit, tentunya.Setelah mengatakan bahwa Anda membutuhkannya, sekarang saya akan mengatakan bahwa Anda benar-benar perlu menghindarinya. Serius, petunjuk anggota menyebalkan. Jauh lebih masuk akal untuk melihat pola desain berorientasi objek yang mencapai tujuan yang sama, atau menggunakan
boost::function
atau apa pun seperti yang disebutkan di atas - dengan asumsi Anda bisa membuat pilihan itu.Jika Anda menyediakan penunjuk fungsi tersebut ke kode yang sudah ada, sehingga Anda benar - benar membutuhkan penunjuk fungsi sederhana, Anda harus menulis fungsi sebagai anggota statis kelas. Fungsi anggota statis tidak mengerti
this
, jadi Anda harus meneruskan objek sebagai parameter eksplisit. Pernah ada idiom yang tidak biasa di sepanjang baris ini untuk bekerja dengan kode C lama yang membutuhkan pointer fungsiKarena
myfunction
benar-benar hanya fungsi normal (masalah lingkup selain), penunjuk fungsi dapat ditemukan dengan cara C normal.EDIT - metode semacam ini disebut "metode kelas" atau "fungsi anggota statis". Perbedaan utama dari fungsi non-anggota adalah, jika Anda mereferensikannya dari luar kelas, Anda harus menentukan cakupan menggunakan
::
operator resolusi cakupan. Misalnya, untuk mendapatkan penunjuk fungsi, gunakan&myclass::myfunction
dan untuk memanggilnya gunakanmyclass::myfunction (arg);
.Hal semacam ini cukup umum ketika menggunakan Win32 API lama, yang awalnya dirancang untuk C daripada C ++. Tentu saja dalam kasus itu, parameternya biasanya LPARAM atau serupa daripada sebuah pointer, dan diperlukan beberapa casting.
sumber
sumber
Contoh minimal runnable
main.cpp
Kompilasi dan jalankan:
Diuji di Ubuntu 18.04.
Anda tidak dapat mengubah urutan tanda kurung atau menghilangkannya. Berikut ini tidak berhasil:
GCC 9.2 akan gagal dengan:
Standar C ++ 11
.*
dan->*
merupakan operator tunggal yang diperkenalkan di C ++ untuk tujuan ini, dan tidak ada di C.Draf standar C ++ 11 N3337 :
.*
dan->*
.sumber
Saya datang ke sini untuk mempelajari cara membuat penunjuk fungsi (bukan penunjuk metode) dari sebuah metode tetapi tidak ada jawaban di sini yang memberikan solusi. Inilah yang saya dapatkan:
Jadi untuk contoh Anda, Anda sekarang akan melakukan:
Sunting:
Menggunakan C ++ 17, ada solusi yang lebih baik:
yang dapat digunakan secara langsung tanpa makro:
Untuk metode dengan pengubah seperti
const
Anda mungkin memerlukan beberapa spesialisasi seperti:sumber
Alasan mengapa Anda tidak dapat menggunakan penunjuk fungsi untuk memanggil fungsi anggota adalah karena penunjuk fungsi biasa biasanya hanya alamat memori dari fungsi tersebut.
Untuk memanggil fungsi anggota, Anda perlu mengetahui dua hal:
Penunjuk fungsi biasa tidak dapat menyimpan keduanya. Pointer fungsi anggota C ++ digunakan untuk menyimpan a), itulah sebabnya Anda perlu menentukan instance secara eksplisit saat memanggil penunjuk fungsi anggota.
sumber
Penunjuk fungsi ke anggota kelas adalah masalah yang sangat cocok untuk menggunakan boost :: function. Contoh kecil:
sumber
Untuk membuat objek baru, Anda dapat menggunakan penempatan baru, seperti yang disebutkan di atas, atau meminta kelas Anda mengimplementasikan metode clone () yang membuat salinan objek. Anda kemudian dapat memanggil metode klon ini menggunakan penunjuk fungsi anggota seperti yang dijelaskan di atas untuk membuat instance baru dari objek. Keuntungan dari kloning adalah terkadang Anda mungkin bekerja dengan pointer ke kelas dasar di mana Anda tidak mengetahui tipe objeknya. Dalam hal ini metode clone () bisa lebih mudah digunakan. Selain itu, clone () akan membiarkan Anda menyalin status objek jika itu yang Anda inginkan.
sumber
Saya melakukan ini dengan std :: function dan std :: bind ..
Saya menulis kelas EventManager ini yang menyimpan vektor penangan dalam unordered_map yang memetakan jenis peristiwa (yang hanya const unsigned int, saya memiliki enum lingkup namespace besar dari mereka) ke vektor penangan untuk jenis peristiwa itu.
Di kelas EventManagerTests saya, saya menyiapkan penangan peristiwa, seperti ini:
Inilah fungsi AddEventListener:
Berikut definisi tipe EventHandler:
Kemudian kembali ke EventManagerTests :: RaiseEvent, saya melakukan ini:
Berikut kode untuk EventManager :: RaiseEvent:
Ini bekerja. Saya mendapatkan panggilan di EventManagerTests :: OnKeyDown. Saya harus menghapus vektor datang waktu pembersihan, tetapi begitu saya melakukannya, tidak ada kebocoran. Meningkatkan acara membutuhkan waktu sekitar 5 mikrodetik di komputer saya, yaitu sekitar tahun 2008. Tidak bisa dibilang super cepat, tapi. Cukup adil selama saya mengetahuinya dan saya tidak menggunakannya dalam kode ultra hot.
Saya ingin mempercepatnya dengan menggulung std :: function dan std :: bind saya sendiri, dan mungkin menggunakan array array daripada unordered_map vektor, tetapi saya belum cukup menemukan cara menyimpan fungsi anggota pointer dan memanggilnya dari kode yang tidak tahu apa-apa tentang kelas yang dipanggil. Jawaban bulu mata terlihat Sangat Menarik ..
sumber