2010-08-01 32 views
11

मैं सी ++ में एक कक्षा को कार्यान्वित करना चाहता हूं जिसमें कॉलबैक है।मैं सी ++ में कॉलबैक कैसे कार्यान्वित करूं?

  • लक्ष्य वस्तु:

    तो मैं मैं एक विधि 2 तर्क हैं कि जरूरत है। (मान लें कि * myObj)

  • लक्ष्य ऑब्जेक्ट के सदस्य फ़ंक्शन के सूचक। (तो मैं क्या कर सकते हैं * myObj-> memberFunc();)

शर्तें हैं:

  • myObj किसी भी वर्ग से हो सकता है।

  • कॉलबैक फ़ंक्शन होने वाला सदस्य फ़ंक्शन गैर स्थैतिक है।

मैं इस बारे में पढ़ रहा हूं लेकिन ऐसा लगता है कि मुझे हाथ से पहले myObj की कक्षा जानने की आवश्यकता है। लेकिन मुझे यकीन नहीं है कि यह कैसे करें। इससे मैं किस तरह निपट सकता हूं? क्या यह सी ++ में संभव है?

यह मेरे मन में कुछ है लेकिन निश्चित रूप से गलत है।

class MyClassWithCallback{ 
public 
    void *targetObj; 
    void (*callback)(int number); 
    void setCallback(void *myObj, void(*callbackPtr)(int number)){ 
     targetObj = myObj; 
     callback = callbackPtr; 
    }; 
    void callCallback(int a){ 
     (myObj)->ptr(a); 
    }; 
}; 
class Target{ 
public 
    int res; 
    void doSomething(int a){//so something here. This is gonna be the callback function};   
}; 

int main(){ 
    Target myTarget; 
    MyClassWithCallback myCaller; 
    myCaller.setCallback((void *)&myTarget, &doSomething); 

}

मैं किसी भी मदद की सराहना करते हैं।

धन्यवाद।

अद्यतन आप में से अधिकांश ने कहा कि निरीक्षण और प्रतिनिधिमंडल, ठीक है, मैं वही हूं जो मैं ढूंढ रहा हूं, मैं एक उद्देश्य-सी/कोको दिमागी लड़का हूं। मेरा वर्तमान कार्यान्वयन आभासी कार्यों के साथ इंटरफेस का उपयोग कर रहा है। क्या मैंने सोचा कि इंटरफ़ेस को परिभाषित करने के बजाय ऑब्जेक्ट और सदस्य फ़ंक्शन पॉइंटर (जैसे बूस्ट!) को पास करने के लिए यह "चालाक" होगा। लेकिन ऐसा लगता है कि हर कोई इस बात से सहमत है कि इंटरफेस सही तरीका है? बूस्ट एक अच्छा विचार प्रतीत होता है, (माना जाता है)

+0

पर्यवेक्षक पैटर्न को "मनाए गए" वर्ग इंटरफ़ेस में परिवर्तन की आवश्यकता होती है, कभी-कभी यह इंटरफ़ेस के बजाय 'फ़ंक्शन' और 'बाइंड' का उपयोग करना बहुत आसान और स्पष्ट होता है। यह भी ध्यान दें, अगर आप हालिया जीसीसी का उपयोग कर रहे हैं, तो आपके पास पहले से ही 'फंक्शन' और 'बाइंड' है इसलिए बूस्ट की कोई आवश्यकता नहीं है। इंटरफेस का उपयोग करते समय फ़ंक्शन/बाइंड का कार्यात्मक प्रोग्रामिंग पैटर अधिक "मानक" डिज़ाइन पैटर्न का उपयोग कर रहा है जिसका अलग अर्थ – Artyom

उत्तर

16

सबसे अच्छा समाधान, boost::bind साथ boost::function का उपयोग , या यदि आपका कंपाइलर tr1/C++ 0x std::tr1::function और std::tr1::bind का उपयोग करता है।

तो यह रूप में सरल हो जाता है:

boost::function<void()> callback; 
Target myTarget; 
callback=boost::bind(&Target::doSomething,&myTarget); 

callback(); // calls the function 

और अपने सेट कॉलबैक हो जाता है:

class MyClassWithCallback{ 
public: 
    void setCallback(boost::function<void()> const &cb) 
    { 
    callback_ = cb; 
    } 
    void call_it() { callback_(); } 
private: 
    boost::function<void()> callback_; 
}; 

नहीं तो आप कुछ अमूर्त वर्ग

struct callback { 
virtual void call() = 0; 
virtual ~callback() {} 
}; 

struct TargetCallback { 
virtual void call() { ((*self).*member)()); } 
void (Target::*member)(); 
Target *self; 
TargetCallback(void (Target::*m)(),Target *p) : 
     member(m), 
     self(p) 
{} 
}; 

और फिर का उपयोग लागू करने की आवश्यकता:

myCaller.setCallback(new TargetCallback(&Target::doSomething,&myTarget)); 

अपनी कक्षा में संशोधित हो जब:

class MyClassWithCallback{ 
public: 
    void setCallback(callback *cb) 
    { 
    callback_.reset(cb); 
    } 
    void call_it() { callback_->call(); } 
private: 
    std::auto_ptr<callback> callback_; 
}; 

और निश्चित रूप से समारोह आप कॉल करने के लिए परिवर्तन नहीं करता है तो आप सिर्फ कुछ इंटरफ़ेस को लागू कर सकते हैं चाहते हैं, जैसे कि इस कॉल के साथ कुछ अमूर्त वर्ग से लक्ष्य प्राप्त करता है, तो।

+0

+1 एक अच्छी फैशन में बढ़ावा देने के लिए –

+0

+1 , बूस्ट :: बाइंड निश्चित रूप से सी ++ के लिए जाने का तरीका है - केवल कॉलबैक – Calvin1602

+0

बूस्ट: बाइंड निश्चित रूप से उत्तर की तलाश में है। हालांकि मुझे शायद बढ़ावा देना होगा। – nacho4d

8

एक चाल इंटरफेस का उपयोग करने के लिए है, इस तरह आपको ऑब्जेक्ट्स में लागू होने पर ऑब्जेक्ट को 'MyClassWithCallback' में विशेष रूप से कक्षा को जानने की आवश्यकता नहीं है, इंटरफेस।

उदा। (छद्म कोड)

struct myinterface 
{ 
    void doSomething()=0; 
}; 

class Target : public myinterface { ..implement doSomething... }; 

और

myinterface *targetObj; 
void setCallback(myinterface *myObj){ 
    targetObj = myObj; 
}; 

कॉलबैक

targetObj->doSomething(); 

कर यह स्थापित करने:

Target myTarget; 
MyClassWithCallback myCaller; 
myCaller.setCallback(myTarget); 
+1

है http://en.wikipedia.org/wiki/Observer_pattern –

5

Observer डिज़ाइन पैटर्न जो आप ढूंढ रहे हैं वह प्रतीत होता है।

3

इसके अलावा, Observer Pattern और signals and slots देखें। यह कई ग्राहकों तक फैलता है।

+0

हां, मैं एक उद्देश्य-सी दुनिया से आया हूं और यह वही है जो मैं लागू करना चाहता हूं। – nacho4d

2

सी ++ में, कक्षा विधियों के पॉइंटर्स का शायद ही उपयोग किया जाता है। तथ्य यह है कि आपने इसमें कहा - यह प्रतिनिधि है और उनके उपयोग की अनुशंसा नहीं की जाती है। उनके बजाय, आपको वर्चुअल फ़ंक्शंस और अमूर्त कक्षाओं का उपयोग करना होगा। हालांकि, सी ++ मेरे लिए इतना शौकीन नहीं होता, अगर यह प्रोग्रामिंग की पूरी तरह से अलग अवधारणाओं का समर्थन नहीं करता है। यदि आप अभी भी प्रतिनिधियों को चाहते हैं, तो आपको "बूस्ट फंक्शनल" (सी + +0 एक्स का हिस्सा) की ओर देखना चाहिए, यह क्लाइंट नाम के बावजूद कक्षाओं के तरीकों को पॉइंटर्स की अनुमति देता है। इसके अलावा, सी ++ बिल्डर में __closure टाइप किया गया है - कंपाइलर के स्तर पर एक प्रतिनिधि का कार्यान्वयन।

पीएस बुरा अंग्रेजी के लिए क्षमा करें ...

4

आप कुछ बुनियादी विकल्प हैं:

1) क्या करना है निर्दिष्ट वर्ग कॉलबैक, उपयोग करने के लिए इतना है कि वस्तु सूचक और सदस्य समारोह सूचक प्रकार जाना जाता है जा रहा है, और हो सकता है कॉलर में इस्तेमाल किया। कक्षा में एक ही हस्ताक्षर के साथ कई सदस्य कार्य हो सकते हैं, जिन्हें आप चुन सकते हैं, लेकिन आपके विकल्प काफी सीमित हैं।

एक बात यह है कि आपने अपने कोड में गलत किया है कि सी ++ में सदस्य फ़ंक्शन पॉइंटर्स और फ्री फ़ंक्शन पॉइंटर्स समान नहीं हैं, और संगत प्रकार नहीं हैं। आपका कॉलबैक पंजीकरण फ़ंक्शन फ़ंक्शन पॉइंटर लेता है, लेकिन आप इसे सदस्य फ़ंक्शन पॉइंटर पास करने का प्रयास कर रहे हैं। अनुमति नहीं हैं। इसके अलावा, "यह" ऑब्जेक्ट का प्रकार सदस्य फ़ंक्शन पॉइंटर के प्रकार का हिस्सा है, इसलिए सी ++ में ऐसी कोई चीज़ नहीं है जो "किसी भी सदस्य फ़ंक्शन के लिए सूचक है जो पूर्णांक लेती है और शून्य लौटाती है"। यह होना चाहिए, "लक्ष्य के किसी भी सदस्य फ़ंक्शन के लिए एक सूचक जो पूर्णांक लेता है और शून्य लौटाता है"। इसलिए सीमित विकल्प।

2) एक इंटरफ़ेस वर्ग में शुद्ध वर्चुअल फ़ंक्शन को परिभाषित करें। कोई भी वर्ग जो कॉलबैक प्राप्त करना चाहता है इसलिए इंटरफ़ेस क्लास से प्राप्त हो सकता है। एकाधिक विरासत के लिए धन्यवाद, यह आपके बाकी वर्ग पदानुक्रम में हस्तक्षेप नहीं करता है। यह जावा में एक इंटरफ़ेस को परिभाषित करने के लगभग बिल्कुल वैसा ही है।

3) कॉलबैक के लिए गैर-सदस्य फ़ंक्शन का उपयोग करें। प्रत्येक वर्ग के लिए जो इसका उपयोग करना चाहता है, आप थोड़ा स्टब फ्री फ़ंक्शन लिखते हैं जो ऑब्जेक्ट पॉइंटर लेता है और उस पर सही सदस्य फ़ंक्शन को कॉल करता है।तो आपके मामले में आप होगा:

dosomething_stub(void *obj, int a) { 
    ((Target *)obj)->doSomething(a); 
} 

4) टेम्प्लेट का उपयोग करके:

template<typename CB> class MyClassWithCallback { 
    CB *callback; 
public: 
    void setCallback(CB &cb) { callback = &cb; } 
    void callCallback(int a) { 
     callback(a); 
    } 
}; 

class Target { 
    void operator()(int a) { /* do something; */ } 
}; 

int main() { 
    Target t; 
    MyClassWithCallback<T> caller; 
    caller.setCallback(t); 
} 

आप टेम्पलेट का उपयोग कर सकते हैं या नहीं निर्भर करता है कि क्या आपके ClassWithCallback कुछ बड़े पुराने ढांचे का हिस्सा है - तो अगर तो यह हो सकता है संभव नहीं है (सटीक होने के लिए: कुछ और चाल की आवश्यकता हो सकती है, जैसे एक टेम्पलेट क्लास जो वर्चुअल सदस्य फ़ंक्शन वाले गैर-टेम्पलेट वर्ग से प्राप्त होती है), क्योंकि आप प्रत्येक कॉलबैक प्राप्तकर्ता के लिए एक बार पूरे ढांचे को तुरंत चालू नहीं कर सकते हैं।

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