समस्या यह है कि B
का सदस्य फ़ंक्शन A
का सदस्य फ़ंक्शन नहीं है, भले ही B
A
से निकला है। यदि आपके पास void (A::*)()
है, तो आप ऑब्जेक्ट के वास्तविक व्युत्पन्न प्रकार की परवाह किए बिना, किसी भी A *
पर इसका आह्वान कर सकते हैं।
(इसी सिद्धांत निश्चित रूप से भी एक A &
पर लागू होगा।)
मान लें B
A
से निकला है, और C
A
से निकला है; यह एक void (B::*)()
(माना) एक void (A::*)()
के रूप में विचार करने के लिए संभव थे थे, एक कुछ इस तरह करने में सक्षम हो जाएगा:
A *c=new C;
A *b=new B;
void (A::*f)()=&B::fn;//fn is not defined in A
(c->*f)();
और B
के सदस्य समारोह प्रकार C
की एक वस्तु पर कहा जा सकता है। परिणाम सबसे अच्छा अप्रत्याशित होगा।
class Callback {
public:
virtual ~Callback() {
}
virtual Do(int a)=0;
};
तब समारोह है कि कॉलबैक कॉल में से एक लेता है:
उदाहरण कोड के आधार पर, और बढ़ावा तरह कुछ की गैर-उपयोग यह सोचते हैं, मैं एक वस्तु के रूप कॉलबैक की संरचना करने के इच्छुक होगी इन वस्तुओं किसी भी तरह के बजाय एक सादे समारोह सूचक:
class A {
protected:
void doSomething(Callback *c) {
c->Do(1234);
}
};
फिर आप व्युत्पन्न समारोह आपको बुला रहा में रुचि रखते हैं प्रति एक कॉलबैक हो सकता था। छदाम, उदाहरण के लिए के लिए:
class B:public A {
public:
void runDoIt() {
DoItCallback cb(this);
this->doSomething(&cb);
}
protected:
void doIt(int foo) {
// whatever
}
private:
class DoItCallback:public Callback {
public:
DoItCallback(B *b):b_(b) {}
void Do(int a) {
b_->doIt(a);
}
private:
B *b_;
};
};
बॉयलरप्लेट पर वापस काटने कॉलबैक में सदस्य समारोह सूचक डाल करने के लिए, के बाद से व्युत्पन्न कॉलबैक एक विशिष्ट प्रकार की वस्तुओं से निपटने के लिए नि: शुल्क है होगा की एक स्पष्ट तरीका है। इसके लिए कॉलबैक में थोड़ा और अधिक सामान्य बनाना होगा, कि जब में वापस बुलाया यह ग्रुप बी के एक वस्तु पर एक मनमाना सदस्य समारोह आह्वान होगा:
class BCallback:public Callback {
public:
BCallback(B *obj,void (B::*fn)(int)):obj_(obj),fn_(fn) {}
void Do(int a) {
(obj_->*fn_)(a);
}
private:
B *obj_;
void (B::*fn_)(int);
};
यह इस तरह छदाम बनाना होगा:
void B::runDoIt() {
BCallback cb(this,&B::doIt);
this->doSomething(&cb);
}
यह संभवतः "सुधार" किया जा सकता है, हालांकि नहीं सभी पाठकों यह काफी है कि रास्ते में देख सकते हैं, यह templating द्वारा:
template<class T>
class GenericCallback:public Callback {
public:
GenericCallback(T *obj,void (T::*fn)(int)):obj_(obj),fn_(fn) {}
void Do(int a) {
(obj_->*fn_)(a);
}
private:
T *obj_;
void (T::*fn_)(int);
};
इस का उपयोग करना, ऊपर runDoIt समारोह बन सकता है:
void B::runDoIt() {
GenericCallback<B> cb(this,&B::doIt);
this->doSomething(&cb);
}
(जेनेरिक कॉलबैक सदस्य फ़ंक्शन पॉइंटर पर भी टेम्पलेट किया जा सकता है, हालांकि अधिकांश मामलों में यह कोई व्यावहारिक लाभ प्रदान करने की संभावना नहीं है। यह सिर्फ और टाइपिंग है।)
मुझे अच्छी तरह से बाहर निकलने के लिए इस तरह की संरचनाएं मिल रही हैं, क्योंकि इसे विरासत की आवश्यकता नहीं है। इसलिए इस कोड पर कुछ प्रतिबंध लगाए जाते हैं जिन्हें वापस बुलाया जाना है, जो कि मेरे दिमाग में हमेशा एक अच्छी बात है, और मैंने पाया है कि पूरी तरह से खत्म करने के लिए कठिन होने वाली क्रियापदता से अधिक है। उदाहरण के आधार पर असंभव यह बताने के लिए कि क्या यह दृष्टिकोण वास्तव में उपयुक्त होगा, हालांकि ...
मैं इस दृष्टिकोण को दूसरा करूंगा। यहां बढ़ावा देने का उपयोग बहुत समझ में आता है, उन्होंने इस तरह की चीज में बहुत सारे प्रयास किए हैं। – sstock
मैं कुछ भी बढ़ावा देने के लिए थोड़ा संकोच करता था, लेकिन मैं इसे आज़माने वाला हूं। जैसा कि आपने यहां वर्णित किया है, यह कम या ज्यादा काम करता है! –