2009-06-16 15 views
34

के रूप में एक सी ++ वर्ग के सदस्य समारोह का उपयोग करते हुए मैं एक सी पुस्तकालय एक कॉलबैक फ़ंक्शन की जरूरत है कि कुछ प्रसंस्करण अनुकूलित करने के लिए पंजीकृत किया जाना है। कॉलबैक फ़ंक्शन का प्रकार int a(int *, int *) है।एक सी कॉलबैक फ़ंक्शन

मैं लिख रहा हूँ सी ++ निम्नलिखित और एक सी रजिस्टर करने के लिए कोशिश ++ कॉलबैक समारोह के रूप में वर्ग समारोह के समान कोड:

In constructor 'A::A()', 
error: 
argument of type ‘int (A::)(int*, int*)’ does not match ‘int (*)(int*, int*)’. 

मेरे सवालों का:

class A { 
    public: 
    A(); 
    ~A(); 
    int e(int *k, int *j); 
}; 

A::A() 
{ 
    register_with_library(e) 
} 

int 
A::e(int *k, int *e) 
{ 
    return 0; 
} 

A::~A() 
{ 

} 

संकलक त्रुटि निम्नलिखित फेंकता

  1. सबसे पहले सी ++ कक्षा मेमबर फ़ंक्शन को पंजीकृत करना संभव है जैसे कि मैं ऐसा करने की कोशिश कर रहा हूं और यदि ऐसा है ओउ? (मैंने 0.पर 32.8 पढ़ा है। लेकिन मेरी राय में यह समस्या का समाधान नहीं करता है)
  2. क्या इससे निपटने के लिए एक वैकल्पिक/बेहतर तरीका है?

उत्तर

37

यदि सदस्य कार्य स्थिर है तो आप ऐसा कर सकते हैं।

कक्षा ए के गैर स्थैतिक सदस्य कार्यों का class A* प्रकार का एक पहला पैरामीटर है जो सूचक से मेल खाता है। यही कारण है कि आप केवल उन्हें रजिस्टर सकता है अगर कॉलबैक के हस्ताक्षर भी class A* प्रकार का पहला पैरामीटर पड़ा है।

+0

हां। वह समाधान काम किया। मुझे भ्रमित करता है कि कंपाइलर त्रुटि int (ए ::) (ए *, int *, int *) 'int() (int, int *)' – Methos

+0

से मेल नहीं खाता है, लेकिन यह डालकर (ए: :) जिसका मतलब है कि फ़ंक्शन कक्षा ए का हिस्सा है, जो वहां से 'यह' सूचक इंगित करता है। – GManNickG

+0

मैं सिर्फ उत्सुक हूं ... क्या यह मानक में निर्दिष्ट है? मैंने बस कक्षाओं के अनुभाग में देखा और इसे नहीं मिला। फिर भी, बहुत दिलचस्प है। मैं बस यह नहीं सोचूंगा कि हर कंपाइलर को इस तरह से गैर स्थैतिक सदस्य कार्यों को संभालना होगा। – Tom

1

सदस्य फ़ंक्शन का उपयोग करने में समस्या यह है कि इसे किसी ऑब्जेक्ट की आवश्यकता होती है जिस पर कार्य करना है - और सी वस्तुओं के बारे में नहीं जानता है।

सबसे आसान तरीका निम्न करने के लिए किया जाएगा:

//In a header file: 
extern "C" int e(int * k, int * e); 

//In your implementation: 
int e(int * k, int * e) { return 0; } 
+0

तो क्या आप इसका मतलब सदस्य कार्य नहीं करते हैं? – Methos

+0

इस मामले में, हाँ। आईएमओ एक स्टैंडअलोन फ़ंक्शन का उपयोग करके प्रदान की जाने वाली अधिक सादगी में शामिल encapsulation की कमी से अधिक है। – PaulJWilliams

7

समस्या यह है कि विधि = कार्य है। संकलक ऐसा ही कुछ करने के लिए अपने विधि बदलना होगा:

int e(A *this, int *k, int *j); 

इसलिए, यह आप इसे पारित नहीं कर सकते हैं सुनिश्चित करें, क्योंकि वर्ग उदाहरण तर्क के रूप में पारित नहीं किया जा सकता है। चारों ओर काम करने का एक तरीका है विधि को स्थिर के रूप में बनाना, इस तरह यह अच्छा प्रकार होगा। लेकिन यह कोई वर्ग उदाहरण नहीं होगा, और गैर स्थैतिक वर्ग के सदस्यों तक पहुंच होगी।

दूसरा तरीका एक स्थिर पॉइंटर के साथ एक समारोह को पहली बार शुरू करने के लिए घोषित करना है। फ़ंक्शन केवल कॉल को कक्षा में रीडायरेक्ट करता है:

int callback(int *j, int *k) 
{ 
    static A *obj = new A(); 
    a->(j, k); 
} 

फिर आप कॉलबैक फ़ंक्शन पंजीकृत कर सकते हैं।

5

खैर ... यदि आप एक Win32 मंच पर हैं वहाँ हमेशा बुरा Thunking तरीका है ...

Thunking in Win32: Simplifying callbacks to non-static member functions

यह एक समाधान है लेकिन मैं इसे इस्तेमाल करने की सलाह नहीं है।
यह एक अच्छा विवरण है और यह पता करने के लिए यह मौजूद है अच्छा है।

13

तुम भी ऐसा कर सकते हैं, तो सदस्य समारोह स्थिर नहीं है, लेकिन यह थोड़ा अधिक काम की आवश्यकता है (यह भी Convert C++ function pointer to c function pointer देखें):

#include <stdio.h> 
#include <functional> 

template <typename T> 
struct Callback; 

template <typename Ret, typename... Params> 
struct Callback<Ret(Params...)> { 
    template <typename... Args> 
    static Ret callback(Args... args) {      
     func(args...); 
    } 
    static std::function<Ret(Params...)> func; 
}; 

template <typename Ret, typename... Params> 
std::function<Ret(Params...)> Callback<Ret(Params...)>::func; 

void register_with_library(int (*func)(int *k, int *e)) { 
    int x = 0, y = 1; 
    int o = func(&x, &y); 
    printf("Value: %i\n", o); 
} 

class A { 
    public: 
     A(); 
     ~A(); 
     int e(int *k, int *j); 
}; 

typedef int (*callback_t)(int*,int*); 

A::A() { 
    Callback<int(int*,int*)>::func = std::bind(&A::e, this, std::placeholders::_1, std::placeholders::_2); 
    callback_t func = static_cast<callback_t>(Callback<int(int*,int*)>::callback);  
    register_with_library(func);  
} 

int A::e(int *k, int *j) { 
    return *k - *j; 
} 

A::~A() { } 

int main() { 
    A a; 
} 

यह उदाहरण अर्थ में पूरा हो गया है कि यह संकलित:

g++ test.cpp -std=c++11 -o test 

आपको c++11 ध्वज की आवश्यकता होगी। कोड में आप देखते हैं कि register_with_library(func) कहा जाता है, जहां func एक स्थिर फ़ंक्शन गतिशील रूप से सदस्य फ़ंक्शन e से जुड़ा हुआ है।

+0

कूल! मैं हमेशा यह जानना चाहता हूं कि यह कैसे करें। – Jacko

+0

क्या होगा यदि सी कॉलबैक फॉर्म int __stdcall कॉलबैक (int *, int *) के रूप में है? – Jacko

+0

@ जैको। एमएमएम ... यह स्टैक क्लीनअप के लिए जिम्मेदार कैली/कॉलर के बारे में है, है ना? मुझे नहीं पता ... मैं विंडोज के बारे में सब कुछ भूल गया। :-) –

संबंधित मुद्दे