2010-03-25 28 views
9

Trong chương trình của tôi C++, tôi cần phải gọi đây là c API:Làm thế nào tôi có thể vượt qua một chức năng C thành viên ++ để một API C như một tham số

GConn* gnet_conn_new (const gchar *hostname, 
         gint port, 
         GConnFunc func); 

nơi GConnFunc được định nghĩa là:

void (*GConnFunc) (GConn *conn); 

câu hỏi của tôi là nếu tôi có một ++ lớp C và có một hàm thành viên như:

Class A { 
public: 
    A(); 
    void my_func (GConn* conn); 
} 

Trong A::A() Constructor của tôi, làm thế nào tôi có thể vượt qua this->myfunc đến gnet_conn_new làm thông số GConnFunc?

Cảm ơn bạn.

+0

Bản sao được đề xuất (http://stackoverflow.com/questions/130322/how-do-you-pass-a-member-function-pointer) không * không * có vẻ trùng lặp. Nó thảo luận về việc truyền các con trỏ tới các thành viên trong một ngữ cảnh C++. – dmckee

Trả lời

11

Hầu hết các API cung cấp luận cứ một con trỏ cỡ 'dữ liệu người dùng', mà sẽ trông như thế này:

GConn* gnet_conn_new (const gchar *hostname, 
        gint port, 
        GConnFunc func, 
        void* user_data); 

này sẽ cho phép bạn vượt qua một ví dụ trong user_data và có chức năng C mong muốn các chức năng thành viên như thế này:

void my_func(GConn *conn, void* user_data) 
{ 
    ((MyClass*)user_data)->MyMemberFunc(conn); 
} 

Có lẽ API của bạn có thông số 'dữ liệu người dùng thay thế hoặc tương tự' ở đâu đó. Nếu không, bạn không thể thực sự làm điều đó nếu không có hình cầu hoặc thống kê.

3

Bạn sẽ cần một hàm bao bọc để xử lý việc này, hoặc bạn có thể làm cho my_func tĩnh (giả sử nó không cần truy cập bất kỳ biến mẫu) nào.

2

Chức năng thành viên không tĩnh trong lớp C++ có thông số "this" bị ẩn. Nếu bạn giả thuyết có thể chuyển nó sang C, hàm sẽ dịch như:

void A_my_func (A * const this, GConn* conn); 

Không có thực sự là một cách để làm chuyển đổi này trong mã của bạn tự động, mặc dù bạn có thể viết một hàm wrapper bằng cách sử dụng nguyên mẫu ở trên và vượt qua một con trỏ đến nó đến một hàm C.

Cách thông thường để xử lý việc này là chuyển một hàm miễn phí (không phải thành viên) hoặc một hàm tĩnh lớp. Cả hai loại này đều không có thông số ẩn.

2

Câu trả lời ngắn gọn, bạn không thể.

Long trả lời:

Với đủ mất nhiều thời gian bởi API bạn cần phải gọi bạn có thể dàn dựng một chức năng mà bạn chỉ cần đăng ký với và gọi như một trung gian. Thông thường các chức năng gọi lại cho phép bạn bao gồm dữ liệu phụ được truyền cho hàm đó cùng với thông tin được tạo bởi đối tượng thực hiện cuộc gọi lại. Nó thường được gọi là một cái gì đó như "client_data" và là loại void * hoặc dài. Khi trường hợp này xảy ra, bạn có thể sử dụng dữ liệu này để bao gồm đủ thông tin để gọi hàm bạn muốn trên cá thể bạn muốn, chẳng hạn như tung vào hàm boost :: function <>.

Lưu ý rằng chức năng trung gian này ủy nhiệm cho chức năng thành viên của bạn có thể là thành viên tĩnh hoặc chức năng miễn phí.

Rất tiếc, bạn không có tùy chọn đó ở đây nên công việc của bạn sẽ khó khăn gấp đôi. Bạn thực sự cần một số cách để đảm bảo rằng chính xác trường hợp được cung cấp thông báo và không có cách nào để bạn xác định cá thể đó từ dữ liệu của cuộc gọi lại.Có một vài tùy chọn có thể có hoặc không hoạt động cho bạn:

  1. đảm bảo bạn không bao giờ sử dụng nhiều trường hợp làm mục tiêu gọi lại. Đăng ký trường hợp này với một singleton hoặc toàn cầu của một số loại theo dõi một ví dụ của một thời gian để tham chiếu các sự kiện thuộc loại này.

  2. Đăng ký bao nhiêu trường hợp tùy thích và chỉ cần đảm bảo tất cả các trường hợp nhận được thư và sau đó xử lý hoặc không xử lý. Bạn có thể sử dụng một loại 'chuỗi trách nhiệm' ở đây, nơi mục tiêu được cho cơ hội để đối phó với một sự kiện và sau đó trả về một cái gì đó cho phép vòng lặp biết liệu nó có nên tiếp tục hay dừng lại không.

Tóm lại, không có cách nào trực tiếp để làm những gì bạn muốn nhưng có thể có câu trả lời để nhận những gì bạn cần nếu bạn cân nhắc các tùy chọn. Bất kỳ hàm nào được sử dụng như một hàm gọi lại được cung cấp cho một hàm API C phải được tham chiếu như một con trỏ hàm, không phải là một con trỏ thành viên thuộc bất kỳ loại nào ... và không may là không phải là một hàm functor. C không biết làm thế nào để đối phó với những điều đó, do đó, gọi lại của bạn phải là một chức năng miễn phí hoặc một thành viên tĩnh.

Các vấn đề liên quan