Không có gì sai khi sử dụng con trỏ hàm. Tuy nhiên, con trỏ đến các hàm thành viên không tĩnh không giống như các con trỏ hàm thông thường: các hàm thành viên cần được gọi trên một đối tượng được truyền như một đối số ngầm định cho hàm. Chữ ký của chức năng thành viên của bạn ở trên, do đó
void (aClass::*)(int, int)
thay vì loại bạn cố gắng sử dụng
void (*)(int, int)
Một cách tiếp cận có thể bao gồm việc tạo hàm thành viên static
trong trường hợp đó nó không yêu cầu bất kỳ đối tượng nào được gọi và bạn có thể sử dụng nó với kiểu void (*)(int, int)
.
Nếu bạn cần truy cập bất kỳ thành viên không tĩnh nào trong lớp của mình và bạn cần gắn với con trỏ hàm, ví dụ: vì hàm là một phần của giao diện C, tùy chọn tốt nhất của bạn là luôn chuyển một void*
hàm cho hàm của bạn, lấy con trỏ hàm và gọi thành viên của bạn thông qua một hàm chuyển tiếp lấy một đối tượng từ void*
và sau đó gọi hàm thành viên.
Trong một giao diện C ++ thích hợp, bạn có thể muốn xem hàm của bạn có đối số mẫu cho các đối tượng hàm để sử dụng các kiểu lớp tùy ý. Nếu việc sử dụng một giao diện mẫu là không mong muốn, bạn nên sử dụng một cái gì đó như std::function<void(int, int)>
: bạn có thể tạo một đối tượng chức năng có thể gọi phù hợp cho chúng, ví dụ: sử dụng std::bind()
.
Các phương pháp tiếp cận kiểu an toàn bằng cách sử dụng đối số mẫu cho kiểu lớp hoặc kiểu phù hợp std::function<...>
sẽ thích hợp hơn là sử dụng void*
giao diện vì chúng loại bỏ khả năng xảy ra lỗi do truyền sang kiểu sai.
Để làm rõ cách sử dụng con trỏ hàm để gọi một hàm thành viên, đây là một ví dụ:
// the function using the function pointers:
void somefunction(void (*fptr)(void*, int, int), void* context) {
fptr(context, 17, 42);
}
void non_member(void*, int i0, int i1) {
std::cout << "I don't need any context! i0=" << i0 << " i1=" << i1 << "\n";
}
struct foo {
void member(int i0, int i1) {
std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "\n";
}
};
void forwarder(void* context, int i0, int i1) {
static_cast<foo*>(context)->member(i0, i1);
}
int main() {
somefunction(&non_member, 0);
foo object;
somefunction(&forwarder, &object);
}