2008-09-30 11 views
13

पर समारोह सूचक कॉलिंग?मैं एक समारोह सूचक द्वारा परिभाषित किया गया है एक सी ++ एक विशिष्ट वस्तु दृष्टान्त

class A 
{ 
private: 
    EventFunction handler; 

public: 
    void SetEvent(EventFunction func) { handler = func; } 

    void EventOne() { handler(1); } 
}; 

class B 
{ 
private: 
    A a; 
public: 
    B() { a.SetEvent(EventFromA); } // What do I do here? 

    void EventFromA(int nEvent) { // do stuff } 
}; 

संपादित करें: ओरियन विकल्पों बूस्ट जैसे प्रस्तावों ने कहा:

boost::function<int (int)> f; 
X x; 
f = std::bind1st(
     std::mem_fun(&X::foo), &x); 
f(5); // Call x.foo(5) 

दुर्भाग्य से बूस्ट मेरे लिए एक विकल्प नहीं है। क्या कोई "करीइंग" फ़ंक्शन है जिसे सी ++ में लिखा जा सकता है जो किसी सामान्य फ़ंक्शन पॉइंटर में किसी सदस्य फ़ंक्शन में पॉइंटर की इस तरह की रैपिंग करेगा?

+0

हाँ, वहाँ एक सी ++ currying समारोह, कहा जाता tr1 :: बाँध या बढ़ावा देने :: बाँध है! और हां, करीबी परिणाम रखने के लिए एक रैपर है। इसे tr1 :: फ़ंक्शन या बूस्ट :: फ़ंक्शन कहा जाता है। – Aaron

+0

क्या कोई कृपया C++ 11 std :: फ़ंक्शन का उपयोग कर कोड स्निपेट उत्तर प्रदान कर सकता है? मैं सी ++ सीख रहा हूं और यह मुझे भ्रमित कर रहा है, क्योंकि मुझे ऐसी मूलभूत चीज़ उपलब्ध होने की उम्मीद है, फिर भी नीचे दिए गए सभी उत्तर जो बूस्ट या सी ++ 11 पर वापस आते हैं, वास्तव में कोड स्निपेट/हाउटो प्रदान नहीं करते हैं। – Dima

उत्तर

9

मैं अत्यधिक डॉन की सलाह देते हैं: अधिकांश सी पुस्तकालयों कि एक कॉलबैक फ़ंक्शन ले आमतौर पर भी आप अपने मनपसंद (प्रकार void* की आमतौर पर), जो आप अपने वर्ग bootstrap करने के लिए उपयोग कर सकते हैं, के रूप में इसलिए की एक अतिरिक्त तर्क से गुजरने की अनुमति क्लुगस्टन की उत्कृष्ट फास्टडिलेगेट लाइब्रेरी। यह उन सभी चीजों को प्रदान करता है जो आप वास्तविक प्रतिनिधि की अपेक्षा करते हैं और ज्यादातर मामलों में कुछ एएसएम निर्देशों तक संकलित करते हैं। साथ-साथ लेख सदस्य फ़ंक्शन पॉइंटर्स पर भी एक अच्छा पठन है।

http://www.codeproject.com/KB/cpp/FastDelegate.aspx

+0

वहां बहुत अच्छी जानकारी है। – fryguybob

+0

मुझे ध्यान रखना चाहिए कि सी ++ 11 समर्थन के साथ आपको संभव होने पर 'std :: function' का उपयोग करना चाहिए। FastDelegate को कुछ समय में अपडेट नहीं किया गया है और शायद हमेशा के लिए काम नहीं करेगा। –

1

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

typedef void (*B::EventFunction)(int nEvent);

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

  • मेक बी एक आधार वर्ग है, तो एक-दूसरे वर्ग कि कहा जा सकता है के लिए एक आभासी समारोह को ओवरराइड। फिर एक फ़ंक्शन पॉइंटर के बजाय बी को पॉइंटर स्टोर करता है। बहुत साफ
  • यदि आप किसी विशिष्ट वर्ग प्रकार को फ़ंक्शन को बाध्य नहीं करना चाहते हैं, यहां तक ​​कि एक बेस क्लास (और मैं आपको दोष नहीं दूंगा), तो मेरा सुझाव है कि आप उस फ़ंक्शन को बनाते हैं जिसे स्थैतिक फ़ंक्शन कहा जाता है: "static void EventFrom A(int nEvent);" । फिर आप इसे बी के ऑब्जेक्ट के बिना सीधे कॉल कर सकते हैं, लेकिन शायद आप इसे बी के विशिष्ट उदाहरण को कॉल करना चाहते हैं (जब तक कि बी एक सिंगलटन न हो)।
  • तो यदि आप बी के विशिष्ट उदाहरण को कॉल करने में सक्षम होना चाहते हैं, लेकिन गैर-बी को भी कॉल करने में सक्षम होना चाहते हैं, तो आपको अपने कॉलबैक फ़ंक्शन में कुछ और पास करने की आवश्यकता है ताकि कॉलबैक फ़ंक्शन सही ऑब्जेक्ट को कॉल कर सके । अपने फ़ंक्शन को स्थिर के रूप में बनाएं, और एक शून्य * पैरामीटर जोड़ें जिसे आप बी

अभ्यास में आप इस समस्या के दो समाधान देखें: विज्ञापन प्रणाली जहां आप एक शून्य * पास करते हैं और घटना, और बेस क्लास में वर्चुअल फ़ंक्शन के साथ पदानुक्रम, जैसे विंडोिंग सिस्टम

4

आप C++ FAQ by Marshall Cline जो भी आप पूरा करने की कोशिश कर रहे हैं, उसके लिए उपयोगी हो सकता है।

2

pointers to members पढ़ें। व्युत्पन्न वर्ग पर एक विधि को कॉल करने के लिए, बेस क्लास में वर्चुअल और ओवररीन के रूप में बेस क्लास में विधि घोषित की जानी चाहिए और आपके पॉइंटर को बेस क्लास विधि को इंगित करना चाहिए। pointers to virtual members के बारे में अधिक जानकारी।

0

यह कुछ हद तक स्पष्ट नहीं है कि आप यहां क्या करने की कोशिश कर रहे हैं। क्या स्पष्ट है कि फ़ंक्शन पॉइंटर्स रास्ता नहीं है।

शायद आप जो खोज रहे हैं वह विधि के लिए सूचक है।

+0

दूसरा बिंदु। यदि आप अधिक जानकारी प्रदान करते हैं तो हम और सहायता प्रदान कर सकते हैं। –

11

कच्चे सी ++ फ़ंक्शन पॉइंटर्स से भागें, और इसके बजाय std::function का उपयोग करें।

यदि आप पुराने स्टूडियो 2008 जैसे विजुअल स्टूडियो 2008 का उपयोग कर रहे हैं, तो आप C12+ 11 के लिए कोई समर्थन नहीं रखते हैं, तो आप boost::function का उपयोग कर सकते हैं।
boost:function और std::function वही बात है - उन्होंने सी ++ 11 के लिए एसडीडी लाइब्रेरी में काफी बढ़ावा देने वाली चीजें खींची हैं।

नोट: यदि आप माइक्रोसॉफ्ट एक के बजाय बढ़ावा समारोह प्रलेखन पढ़ सकते हैं के रूप में यह आसान है समझने के लिए

+0

या tr1 :: फ़ंक्शन और tr1 :: बाइंड। – luke

+0

... जो एक ही बात है :) – jkp

11

आप किसी एक वस्तु उदाहरण के vtable में सूचकांक के लिए समारोह संकेत का उपयोग कर सकते हैं। इसे member function pointer कहा जाता है। "। *":

class A; 
class B; 
typedef void (B::*EventFunction)(int nEvent) 

और उसके बाद: अपने वाक्य रचना और "& ::" ऑपरेटर का उपयोग करने के लिए बदलने के लिए की आवश्यकता होगी

class A 
{ 
private: 
    EventFunction handler; 

public: 
    void SetEvent(EventFunction func) { handler = func; } 

    void EventOne(B* delegate) { ((*delegate).*handler)(1); } // note: ".*" 
}; 

class B 
{ 
private: 
    A a; 
public: 
    B() { a.SetEvent(&B::EventFromA); } // note: "&::" 

    void EventFromA(int nEvent) { /* do stuff */ } 
}; 
0

मैं इस सटीक बात के लिए कक्षाओं का एक सेट है कि मैं अपने सी ++ ढांचे में उपयोग करता हूं।

http://code.google.com/p/kgui/source/browse/trunk/kgui.h

मैं कैसे संभाल यह प्रत्येक वर्ग के समारोह के रूप में एक कॉलबैक एक स्थिर समारोह है कि यह करने के लिए ऑब्जेक्ट प्रकार बांधता की जरूरत है इस्तेमाल किया जा सकता है। मेरे पास मैक्रोज़ का एक सेट है जो इसे स्वचालित रूप से करता है। यह एक ही नाम के साथ एक स्थिर कार्य करता है जो "सीबी_" उपसर्ग और क्लास ऑब्जेक्ट पॉइंटर का एक अतिरिक्त पहला पैरामीटर है।

क्लास प्रकारों को चेक करें KGUICallBack और विभिन्न पैरामीटर संस्करणों को विभिन्न पैरामीटर संयोजनों को संभालने के लिए।

#define CALLBACKGLUE(classname , func) static void CB_ ## func(void *obj) {static_cast< classname *>(obj)->func();} 
#define CALLBACKGLUEPTR(classname , func, type) static void CB_ ## func(void *obj,type *name) {static_cast< classname *>(obj)->func(name);} 
#define CALLBACKGLUEPTRPTR(classname , func, type,type2) static void CB_ ## func(void *obj,type *name,type2 *name2) {static_cast< classname *>(obj)->func(name,name2);} 
#define CALLBACKGLUEPTRPTRPTR(classname , func, type,type2,type3) static void CB_ ## func(void *obj,type *name,type2 *name2,type3 *name3) {static_cast< classname *>(obj)->func(name,name2,name3);} 
#define CALLBACKGLUEVAL(classname , func, type) static void CB_ ## func(void *obj,type val) {static_cast< classname *>(obj)->func(val);} 
2

आप एक सी पुस्तकालय के साथ इंटरफ़ेस रहे हैं, तो आप एक वर्ग के सदस्य समारोह boost::bind की तरह कुछ का उपयोग किए बिना उपयोग नहीं कर सकते।


class C 
{ 
public: 
    int Method1(void) { return 3; } 
    int Method2(void) { return x; } 

    int x; 
}; 

// This structure will hold a thunk to 
struct CCallback 
{ 
    C *obj; // Instance to callback on 
    int (C::*callback)(void); // Class callback method, taking no arguments and returning int 
}; 

int CBootstrapper(CCallback *pThunk) 
{ 
    // Call the thunk 
    return ((pThunk->obj) ->* (pThunk->callback))(/* args go here */); 
} 

void DoIt(C *obj, int (C::*callback)(void)) 
{ 
    // foobar() is some C library function that takes a function which takes no arguments and returns int, and it also takes a void*, and we can't change it 
    struct CCallback thunk = {obj, callback}; 
    foobar(&CBootstrapper, &thunk); 
} 

int main(void) 
{ 
    C c; 
    DoIt(&c, &C::Method1); // Essentially calls foobar() with a callback of C::Method1 on c 
    DoIt(&c, &C::Method2); // Ditto for C::Method2 
} 
1

आप उल्लेख है कि बढ़ावा आप के लिए एक विकल्प नहीं है, लेकिन आप TR1 आप के लिए उपलब्ध है?

TR1 बूस्ट लाइब्रेरी के आधार पर फ़ंक्शन, बाइंड और mem_fn ऑब्जेक्ट प्रदान करता है, और आप इसे पहले से ही अपने कंपाइलर के साथ बंडल कर सकते हैं। यह अभी तक मानक नहीं है, लेकिन कम से कम दो कंपाइलर जिन्हें मैंने हाल ही में उपयोग किया है, है।

http://en.wikipedia.org/wiki/Technical_Report_1
http://msdn.microsoft.com/en-us/library/bb982702.aspx

+0

अच्छी सिफारिशें, लेकिन मेरी विशिष्ट परियोजना विरासत वीसी 6 कोड है। यही कारण है कि मैं बेहतर सी ++ डिजाइन विकल्पों * श्वास * के साथ वास्तव में समस्या का समाधान नहीं कर सकता। – fryguybob