2008-09-24 21 views
26

मैं एक वर्ग के भीतर एक सदस्य समारोह को एक समारोह में पास करने की कोशिश कर रहा हूं जो सदस्य फ़ंक्शन क्लास पॉइंटर लेता है। मेरी समस्या यह है कि मुझे यकीन नहीं है कि इस पॉइंटर का उपयोग करके कक्षा में इसे सही तरीके से कैसे किया जाए। क्या किसी के पास सुझाव हैं?आप सदस्य फ़ंक्शन पॉइंटर कैसे पास करते हैं?

class testMenu : public MenuScreen{ 
public: 

bool draw; 

MenuButton<testMenu> x; 

testMenu():MenuScreen("testMenu"){ 
    x.SetButton(100,100,TEXT("buttonNormal.png"),TEXT("buttonHover.png"),TEXT("buttonPressed.png"),100,40,&this->test2); 

    draw = false; 
} 

void test2(){ 
    draw = true; 
} 
}; 

समारोह x.SetButton (...) एक और वर्ग है, जहां "वस्तु" एक टेम्पलेट है में निहित है:

यहाँ वर्ग कि सदस्य समारोह गुजर रहा है की एक प्रति है।

void SetButton(int xPos, int yPos, LPCWSTR normalFilePath, LPCWSTR hoverFilePath, LPCWSTR pressedFilePath, int Width, int Height, void (object::*ButtonFunc)()) { 

    BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height); 

    this->ButtonFunc = &ButtonFunc; 
} 

अगर किसी को कोई सलाह है कि मैं इस फ़ंक्शन को सही तरीके से कैसे भेज सकता हूं ताकि मैं इसे बाद में उपयोग कर सकूं।

उत्तर

32

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

template <class object> 
void MenuButton::SetButton(int xPos, int yPos, LPCWSTR normalFilePath, 
     LPCWSTR hoverFilePath, LPCWSTR pressedFilePath, 
     int Width, int Height, object *ButtonObj, void (object::*ButtonFunc)()) 
{ 
    BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height); 

    this->ButtonObj = ButtonObj; 
    this->ButtonFunc = ButtonFunc; 
} 

में दोनों की जरूरत है:

((ButtonObj)->*(ButtonFunc))(); 

भूल MenuButton::SetButton() करने के लिए अपने ऑब्जेक्ट के लिए सूचक पारित करने के लिए नहीं है:

testMenu::testMenu() 
    :MenuScreen("testMenu") 
{ 
    x.SetButton(100,100,TEXT("buttonNormal.png"), TEXT("buttonHover.png"), 
     TEXT("buttonPressed.png"), 100, 40, this, test2); 
    draw = false; 
} 
+2

'कक्षा के लिए एक सूचक '- क्या यह' वस्तु के लिए एक सूचक 'होना चाहिए? – Vorac

+0

बहुत बहुत धन्यवाद। यह पता नहीं लगा सका कि सिंटैक्स कुछ ऐसा है ((बटनऑबजे) -> * (बटनफंक))() – nathanesau

2

दुर्लभ मामले में है कि आप बोर्लेन्ड सी ++ बिल्डर के साथ विकसित हो के लिए हो और उस दूसरे के साथ काम नहीं करेंगे कि विकास पर्यावरण (वह यह है कि करने के लिए विशिष्ट कोड, कोड लिखने से परहेज नहीं करते देखें सी ++ कंपाइलर्स), आप __closure कीवर्ड का उपयोग कर सकते हैं। मुझे small article about C++Builder closures मिला। वे मुख्य रूप से बोर्लैंड वीसीएल के उपयोग के लिए लक्षित हैं।

+2

एक नहीं बल्कि ... अस्पष्ट समाधान है कि जैसे std::placeholders का उपयोग कर पारित कर सकते हैं लगता है आप एक सदस्य समारोह

class test{ public: int GetMax(int a, int b); ... } 

अपने कोड में है। –

+0

हाँ, यह अस्पष्ट है। :) हालांकि, कॉर्पोरेट भूमि में डेल्फी और सी ++ बिल्डर विरासत कोड चल रहा है। पूरी तरह से होना अच्छा है। – Parappa

5

मानक ओओ का उपयोग करने के लिए आपको बेहतर सेवा नहीं दी जाएगी। एक अनुबंध (वर्चुअल क्लास) परिभाषित करें और अपनी कक्षा में लागू करें, फिर बस अपनी खुद की कक्षा का संदर्भ दें और रिसीवर अनुबंध अनुबंध को कॉल करें।

अपने उदाहरण का उपयोग (मैं 'buttonAction' को 'test2' विधि का नाम बदला गया है):

class ButtonContract 
{ 
    public: 
    virtual void buttonAction(); 
} 


class testMenu : public MenuScreen, public virtual ButtonContract 
{ 
    public: 
    bool draw; 
    MenuButton<testMenu> x; 

    testMenu():MenuScreen("testMenu") 
    { 
     x.SetButton(100,100,TEXT("buttonNormal.png"), 
       TEXT("buttonHover.png"), 
       TEXT("buttonPressed.png"), 
       100, 40, &this); 
     draw = false; 
    } 

    //Implementation of the ButtonContract method! 
    void buttonAction() 
    { 
     draw = true; 
    } 
}; 

रिसीवर विधि में, आप एक ButtonContract के संदर्भ में की दुकान है, तो जब आप निष्पादित करना चाहते बटन की कार्रवाई बस संग्रहीत बटन कंट्रैक्ट ऑब्जेक्ट की 'बटन एक्शन' विधि को कॉल करें।

+0

समस्या यह है कि बटन द्वारा बुलाए जाने वाले विभिन्न कार्यों की निपुण संख्या, यह कार्य बहुत कठिन हो जाएगी। शायद 75 से 100 फ़ंक्शंस हैं जो एक बटन संभवतः कॉल कर सकते हैं। –

+0

एक * isA * रिश्ते की बजाय एक testMenu * हैसा * बटन कंट्रैक्ट (या उनमें से कई)। इस दृष्टिकोण से एक ही क्रिया के साथ दो बटन, या विभिन्न कार्यों के साथ बटन लागू करना मुश्किल हो जाता है। – mabraham

2

अन्य ने आपको बताया है कि इसे सही तरीके से कैसे किया जाए।

this->ButtonFunc = &ButtonFunc; 

ButtonFunc के बाद से एक पैरामीटर है, यह गुंजाइश जब समारोह रिटर्न से बाहर जाना होगा है: लेकिन मैं कोई तुमसे कहा था इस कोड को वास्तव में खतरनाक है हैरान हूँ। आप उसका पता ले रहे हैं। आपको void (object::**ButtonFunc)() (पॉइंटर को सदस्य फ़ंक्शन पर पॉइंटर के प्रकार) का मूल्य मिलेगा और इसे-> बटनफनक को असाइन करें। उस समय आप इसका उपयोग करने का प्रयास करेंगे-> बटनफनक आप स्थानीय पैरामीटर (अब मौजूदा नहीं हैं) के संग्रहण तक पहुंचने का प्रयास करेंगे, और आपका प्रोग्राम शायद क्रैश हो जाएगा।

मैं कमोडोर के समाधान से सहमत हूं।लेकिन तुम

((ButtonObj)->*(ButtonFunc))(); 

के लिये रेखा को बदलने के लिए के बाद से ButtonObj एक सूचक आपत्ति उठाने का है।

6

मुझे पता है कि यह एक पुराना विषय है। लेकिन वहाँ एक सुंदर तरीका

void SetHandler(Max Handler); 

में C++ के साथ इस संभाल करने के लिए 11

#include <functional> 

इस

typedef std::function<int(int,int) > Max; 

की तरह अपने समारोह सूचक की घोषणा अपने पास इस बात की घोषणा अपने समारोह है मान लें कि आप इसे सामान्य फ़ंक्शन पास करते हैं, आप इसे सामान्य

SetHandler(&some function); 
जैसे उपयोग कर सकते हैं

आप इसे इस

test t; 
Max Handler = std::bind(&test::GetMax,&t,std::placeholders::_1,std::placeholders::_2); 
some object.SetHandler(Handler); 
+1

इसके लिए धन्यवाद। यद्यपि आपके पास एक प्रकार है: यह 'std :: प्लेसहोल्डर्स ', बहुवचन है। – Artfunkel

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