Pertanyaannya adalah sebagai berikut: pertimbangkan potongan kode ini:
#include <iostream>
class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};
void function1(void (*function)(int, int))
{
function(1, 1);
}
void test(int a,int b)
{
printf("%d - %d = %d", a , b , a - b);
}
int main (int argc, const char* argv[])
{
aClass a();
function1(&test);
function1(&aClass::aTest); // <-- How should I point to a's aClass::test function?
return 0;
}
Bagaimana saya bisa menggunakan a
's aClass::test
sebagai argumen untukfunction1
? Saya terjebak dalam melakukan ini.
Saya ingin mengakses anggota kelas.
c++
arguments
parameter-passing
function-pointers
pointer-to-member
Jorge Leitao
sumber
sumber
Jawaban:
Tidak ada yang salah dengan menggunakan pointer fungsi. Namun, pointer ke fungsi anggota non-statis tidak seperti pointer fungsi normal: fungsi anggota perlu dipanggil pada objek yang diteruskan sebagai argumen implisit ke fungsi tersebut. Jadi, tanda tangan dari fungsi anggota Anda di atas adalah
daripada tipe yang Anda coba gunakan
Satu pendekatan dapat terdiri dari membuat fungsi anggota
static
dalam hal ini tidak memerlukan objek apa pun untuk dipanggil dan Anda dapat menggunakannya dengan tipevoid (*)(int, int)
.Jika Anda perlu mengakses anggota non-statis kelas Anda dan Anda harus tetap menggunakan pointer fungsi, misalnya, karena fungsinya adalah bagian dari antarmuka C, pilihan terbaik Anda adalah selalu meneruskan a
void*
ke fungsi Anda dengan mengambil fungsi pointer dan memanggil anggota Anda melalui fungsi penerusan yang memperoleh objek darivoid*
dan kemudian memanggil fungsi anggota.Dalam antarmuka C ++ yang tepat, Anda mungkin ingin melihat agar fungsi Anda mengambil argumen templated untuk objek fungsi agar menggunakan tipe kelas arbitrer. Jika menggunakan antarmuka templated tidak diinginkan, Anda harus menggunakan sesuatu seperti
std::function<void(int, int)>
: Anda dapat membuat objek fungsi yang dapat dipanggil yang sesuai untuk ini, misalnya menggunakanstd::bind()
.Pendekatan tipe-aman menggunakan argumen template untuk tipe kelas atau yang sesuai
std::function<...>
lebih disukai daripada menggunakanvoid*
antarmuka karena mereka menghilangkan potensi kesalahan karena cast ke tipe yang salah.Untuk memperjelas cara menggunakan penunjuk fungsi untuk memanggil fungsi anggota, berikut ini contohnya:
sumber
void*
, yang berarti Anda bisa mendapatkan bug yang sangat buruk, karena tidak diketik dicentang lagi.Jawaban @ Pete Becker baik-baik saja tetapi Anda juga dapat melakukannya tanpa meneruskan
class
instance sebagai parameter eksplisit kefunction1
dalam C ++ 11:sumber
void function1(std::function<void(int, int)>)
benar?void function1(std::function<void(int, int)> functionToCall)
dan kemudianfunctionToCall(1,1);
. Saya mencoba mengedit jawabannya tetapi seseorang menolaknya karena tidak masuk akal karena alasan tertentu. Kami akan melihat apakah itu mendapat suara positif di beberapa titik.Fungsi penunjuk ke anggota berbeda dari penunjuk ke fungsi. Untuk menggunakan fungsi anggota melalui penunjuk, Anda memerlukan penunjuk ke sana (jelas) dan objek untuk menerapkannya. Jadi versi yang sesuai
function1
adalahdan menyebutnya:
sumber
function
masukvoid (aClass::*function)(int, int)
adalah tipe, karena itu adalah tipe dalamtypedef void (aClass::*function)(int, int)
.typedef int X;
mendefinisikan tipe;int X;
menciptakan sebuah objek.Sejak 2011, jika Anda bisa berubah
function1
, lakukan seperti ini:( demo langsung )
Perhatikan juga bahwa saya memperbaiki definisi objek Anda yang rusak (
aClass a();
mendeklarasikan fungsi).sumber
Saya mengajukan pertanyaan serupa ( C ++ openframeworks melewati batal dari kelas lain ) tetapi jawaban yang saya temukan lebih jelas jadi di sini penjelasan untuk catatan masa depan:
lebih mudah menggunakan std :: function seperti pada:
lalu panggil sebagai:
atau bahkan lebih mudah:
tempat Anda membuat lambda yang memanggil objek yang menangkapnya dengan referensi
sumber
std::function
dalamdraw
alih-alih menyalinnya di setiap panggilan.Saya membuat fungsi anggota sebagai statis dan semuanya berfungsi:
sumber
Tidak yakin mengapa solusi yang sangat sederhana ini dilewatkan:
Keluaran:
sumber
Jika Anda benar-benar tidak perlu menggunakan instance
a
(misalnya, Anda dapat membuatnya statis seperti jawaban @mathengineer ) Anda cukup memasukkan lambda non-capture. (yang membusuk menjadi penunjuk fungsi)Kotak tongkat sihir
Catatan: jika
aClass
mahal untuk dibangun atau memiliki efek samping, ini mungkin bukan cara yang baik.sumber
Anda bisa berhenti membenturkan kepala sekarang. Berikut adalah pembungkus untuk fungsi anggota untuk mendukung fungsi yang ada yang menggunakan fungsi C biasa sebagai argumen.
thread_local
direktif adalah kuncinya di sini.http://cpp.sh/9jhk3
Harap beri komentar tentang masalah apa pun dengan pendekatan ini.
Jawaban lain gagal memanggil fungsi biasa yang ada
C
: http://cpp.sh/8exunsumber
C
fungsi biasa sebagai argumen.