Tôi có một lớp A mà tôi dự định đưa vào thư viện dùng chung khi nó tương tác với trình điều khiển thiết bị.
Tôi có một lớp B, trong tương lai có thể là C, D, E..., lớp này sẽ sử dụng lớp A từ thư viện dùng chung.
Tôi muốn thiết lập chức năng của các hàm gọi lại trong lớp A để các hàm thành viên không tĩnh của các lớp B, C, D, E... sẽ được lớp A gọi khi một sự kiện cụ thể xảy ra.
Tôi đã tìm kiếm trên Google các hàm gọi lại trong C++ nhưng nhận thấy rằng các định nghĩa gọi lại kiểu C không hỗ trợ các hàm thành viên không tĩnh.
Nó có thể được thực hiện bằng cách sử dụng con trỏ hàm không?
Vui lòng đưa ra một số gợi ý về lệnh gọi lại trong C++ mà không vi phạm khái niệm OOPS.
Tôi cũng đã nghĩ đến một thư viện tên là "Boost" cung cấp chức năng tương tự, nhưng tôi muốn tránh chi phí cho một thư viện bổ sung càng nhiều càng tốt. Có nên sử dụng Boost cho chức năng gọi lại không?
biên tập: B, C, D, E sẽ không chia sẻ bất kỳ hệ thống phân cấp nào, chúng sẽ là các lớp hoàn toàn độc lập. Nhưng tất cả chúng sẽ có các đối tượng thuộc lớp A. Lớp A cũng sẽ có chức năng public để thiết lập chức năng gọi lại.
Nếu bạnthực tếĐể tránh chi phí gần như không quan trọng của các trình bao bọc hàm đa hình, một tùy chọn là đặt các hàm này ở trạng thái tĩnh và để chúng lấy "dữ liệu người dùng"trống*
Các tham số trỏ đến phiên bản thích hợp của lớp mà hàm này thuộc về. bên trong một hàm tĩnh và sau đó chuyển đổi về loại thích hợp:
#include
cấu trúc A{
typedef void (*callback_type)(void*, int);
gọi lại_type gọi lại;
void* user_data;
void set_callback(callback_type cb, void* ud){
gọi lại = cb;
}
void gọi(){ gọi lại(user_data, 42 }
};
cấu trúc B{
static void cb_foo(void* vself, int data){
B* self = static_cast(vself);
tự->foo(dữ liệu);
}
void foo(int data){ std::cout << data * 2 << "\n" }
};
cấu trúc C{
static void cb_bar(void* vself, int data){
C* self = static_cast(vself);
tự->thanh(dữ liệu);
}
void bar(int data){ std::cout << data / 2 << "\n" }
};
int chính(){
Một;
Bb;
a.set_callback(&B::cb_foo, &b);
a.invoke();
C c;
a.set_callback(&C::cb_bar, &c);
a.invoke();
}
Ví dụ trực tiếp trên Ideone.
Tuy nhiên, cá nhân tôi khuyên bạn nên sử dụng std::chức năng
, vì điều trên bị hạn chế nghiêm trọng về số lần gọi lại được chấp nhận. std::chức năng
là một trình bao bọc hàm đa hình, có nghĩa là nó có thể lấy một con trỏ hàm bình thường, một con trỏ hàm thành viên hoặc thậm chí là một functor (đối tượng hàm) và gọi tất cả chúng theo cùng một cách. with cho phép bạn liên kết các tham số với các hàm std::liên kết
Cùng nhau, bạn có thể dễ dàng gọi lại các chức năng thành viên. Boost cũng cung cấp chúng (Tăng cường.Chức năng,Boost.Bind).
#include
#include // C++11
//#include
//#include
cấu trúc A{
std::function gọi lại;
void gọi(){ gọi lại(42);
};
cấu trúc B{
void foo(int data){ std::cout << data * 2 << "\n" }
};
cấu trúc C{
void bar(int data){ std::cout << data / 2 << "\n" }
};
int chính(){
sử dụng không gian tên std::placeholders; // không gian tên dành cho phần giữ chỗ đối số cho std::bind
// không cần thiết cho Boost.Bind
Một;
Bb;
a.callback = std::bind(&B::foo, &b, _1);
a.invoke();
C c;
a.callback = std::bind(&C::bar, &c, _1);
a.invoke();
};
Ví dụ trực tiếp trên Ideone.
về cơ bản std::liên kết
thực hiện tự động những gì bạn phải làm thủ công trong phiên bản đầu tiên, nó lưu con trỏ đối tượng và gọi các hàm thành viên của nó. Tuy nhiên nó không được thông qua trống*
con trỏ để làm điều này, thay vào đó std::liên kết
Trả về một loại chất kết dính khác nhau cho mỗi con trỏ đối tượng khác nhau. đây là thứ bạn cần std::chức năng
bởi vì nó không quan tâm bạn vượt qua nó như thế nào.
Tôi là một lập trình viên xuất sắc, rất giỏi!