2010-03-10 11 views
9

में, इसलिए, मैं एफएमओडी एपीआई का उपयोग कर रहा हूं और यह वास्तव में एक सी एपीआई है।सी एपीआई फ़ंक्शन कॉलबैक सी ++ सदस्य फ़ंक्शन कोड

यह बुरा या कुछ भी नहीं है। इसकी बस यह सी ++ कोड के साथ अच्छी तरह से इंटरफेस नहीं करता है।

उदाहरण के लिए

,

FMOD_Channel_SetCallback(channel, callbackFunc) ; 

का उपयोग कर यह callbackFunc के लिए एक सी शैली समारोह चाहता है, लेकिन मैं इसे एक वर्ग के एक सदस्य समारोह पास करना चाहते हैं।

मैं इसके लिए Win32 चाल का उपयोग कर समाप्त हुआ, जिससे सदस्य कार्य स्थिर हो गया। यह फिर एफएमओडी में कॉलबैक के रूप में काम करता है।

अब मुझे कुछ सदस्यों को स्थिर करने के लिए अपने कोड को अलग करना है, केवल एफएमओडी के सी-नेस के लिए खाते हैं।

मुझे आश्चर्य है कि एफएमओडी में यह संभव है या यदि किसी विशिष्ट सी ++ ऑब्जेक्ट के इंस्टेंस सदस्य फ़ंक्शन (स्थिर फ़ंक्शन नहीं) पर कॉलबैक को जोड़ने के लिए कोई काम है। यह बहुत चिकना होगा।

उत्तर

11

आप सीधे सदस्य फ़ंक्शन पास नहीं कर सकते हैं। एक सदस्य फ़ंक्शन में अंतर्निहित पैरामीटर this और सी फ़ंक्शन नहीं होते हैं।

आपको एक ट्रैम्पोलिन बनाने की आवश्यकता होगी (कॉलबैक का हस्ताक्षर सुनिश्चित नहीं है, तो बस कुछ यादृच्छिक कर रहे हैं)। जहां उस वस्तु सूचक से आता है

extern "C" int fmod_callback(... args ...) 
{ 
    return object->member(); 
} 

एक मुद्दा है। उम्मीद है कि, एफएमओडी आपको एक सामान्य संदर्भ मान देता है जो आपके कॉलबैक के दौरान आपको प्रदान किया जाएगा (आप ऑब्जेक्ट पॉइंटर में पास कर सकते हैं)।

यदि नहीं, तो आपको इसे एक्सेस करने के लिए इसे वैश्विक बनाने की आवश्यकता होगी।

+1

+1 हां, आपको एक ट्रैम्पोलिन बनाना है, लेकिन वे बहुत गड़बड़ कर रहे हैं (यदि आप ग्लोबल्स से बचना चाहते हैं, और वह सब कुछ)! :-(यदि एपीआई को पहले स्थान पर सही ढंग से डिज़ाइन किया गया था .... –

+1

आपको सी ++ सदस्य फ़ंक्शंस फेंकने के बारे में चिंता करने की भी आवश्यकता है। और यह "ट्रैम्पोलिन" शब्द कहां से आया? –

+1

@NeilButterworth - I याद नहीं है कि मैंने पहली बार इसे "ट्रैम्पोलिन" के रूप में वर्णित किया था, लेकिन मेरे उपयोग के लिए एक संदर्भ विकिपीडिया (http://en.wikipedia.org/wiki/Trampoline_%28computers%29) है, जब कोड के टुकड़ों को इंटरफेस करते समय असंगत कॉलिंग सम्मेलन, कॉलर के सम्मेलन को कैली के सम्मेलन में बदलने के लिए एक ट्रैम्पोलिन का उपयोग किया जाता है। –

1

सी विनबैक के लिए केवल एक फ़ंक्शन पॉइंटर (और कोई अतिरिक्त अलग ऑब्जेक्ट पॉइंटर) का उपयोग करना मेरी विनम्र राय में एक टूटा हुआ डिज़ाइन है।

यदि फ़ंक्शन थे, तो FMOD_Channel_SetCallback(channel, callbackFunc, callbackObj), तो आपकी स्थैतिक विधि केवल ऑब्जेक्ट का एक उदाहरण लेती है, फिर callbackObj->func() (जो स्पष्ट रूप से गैर स्थैतिक हो सकती है) पर कॉल करती है।

+1

इसे एफएमओडी लोगों को सुझाव दें! कृप्या! – bobobobo

+1

@bobobobo: डेनिस का जवाब देखें। मुझे लगता है कि एपीआई पहले से ही इसका समर्थन करता है (जाहिर है कि उसने एफएमओडी की तुलना में अधिक है :- पी)। मैं अपने उत्तर को अन्य एपीआई डिजाइनरों के लिए सावधानीपूर्वक कहानी के रूप में रखूंगा, लेकिन कम से कम आपके पास समाधान होगा। –

0

आप एक ट्रैम्पोलिन का उपयोग करें और वस्तु आप एक वैश्विक या स्थिर चर में पर बुलाया सदस्य समारोह प्राप्त करना चाहते हैं के लिए सूचक स्टोर करने के लिए, की जरूरत है यानी

Object *x; 
void callback_trampoline() { x->foobar(); } 
... 
FMOD_Channel_SetCallback(CHANNEL, callback_trampoline); 
4

मैं इसे इस तरह से काम करने वाला लगता है:
आप FMOD_Channel_SetUserData पर कॉल करके कुछ उपयोगकर्ता डेटा चैनल को असाइन कर सकते हैं। यह उपयोगकर्ता डेटा आपके C++ ऑब्जेक्ट के लिए पॉइंटर होना चाहिए जो ईवेंट को संभालता है। फिर आपको सी-स्टाइल कॉलबैक लिखना चाहिए जो उस ऑब्जेक्ट को FMOD_Channel_GetUserData पर कॉल करके निकालता है और फिर उस ऑब्जेक्ट पर आपकी C++ इंस्टेंस विधि को कॉल करता है।

+0

+1 ओह, जीतो! तो, जैसा कि मैंने सोचा था एपीआई उतना टूटा नहीं है। –

2

एक गैर-पोर्टेबल और सुंदर हैकिश समाधान है जिसमें कम से कम थ्रेड-सुरक्षित होने का लाभ होता है, जो "ट्रैम्पोलिन" विधियां नहीं होती हैं।

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

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

उदाहरण के लिए http://www.codeproject.com/KB/cpp/GenericThunks.aspx देखें कि आप कैसे थैंक्स उत्पन्न करने के बारे में जा सकते हैं।