2009-07-30 12 views
19

के साथ वर्चुअल सदस्य फ़ंक्शन की बेस क्लास परिभाषा को कॉल करना मैं सदस्य फ़ंक्शन पॉइंटर का उपयोग करके वर्चुअल फ़ंक्शन के बेस क्लास कार्यान्वयन को कॉल करना चाहता हूं।फ़ंक्शन पॉइंटर

class Base { 
public: 
    virtual void func() { cout << "base" << endl; } 
}; 

class Derived: public Base { 
public: 
    void func() { cout << "derived" << endl; } 

    void callFunc() 
    { 
     void (Base::*fp)() = &Base::func; 
     (this->*fp)(); // Derived::func will be called. 
         // In my application I store the pointer for later use, 
         // so I can't simply do Base::func(). 
    } 
}; 

समारोह के व्युत्पन्न वर्ग कार्यान्वयन उपरोक्त कोड में callFunc से बुलाया जाएगा। क्या कोई तरीका है कि मैं सदस्य फ़ंक्शन पॉइंटर को सहेज सकता हूं जो बेस :: func को इंगित करता है, या मुझे किसी तरह से using का उपयोग करना होगा?

मेरे वास्तविक एप्लिकेशन में मैं बूस्ट :: बाइंड ऑब्जेक्ट को कॉलफंक्शन में बनाने के लिए बूस्ट :: बाइंड का उपयोग करता हूं जिसे बाद में मैं अपने प्रोग्राम के किसी अन्य भाग से func कॉल करने के लिए उपयोग करता हूं। तो अगर बढ़ावा :: बाइंड या बूस्ट :: फ़ंक्शन के पास इस समस्या को हल करने का कोई तरीका है जो भी मदद करेगा।

+0

[सी ++ का संभावित डुप्लिकेट: वर्चुअल सदस्य फ़ंक्शन के मोनोमोर्फिक संस्करण के लिए पॉइंटर?] (Https://stackoverflow.com/questions/5064614/c-pointer-to-monomorphic-version-of-virtual-member- कार्यक्षमता) –

उत्तर

11

जब आप किसी संदर्भ या पॉइंटर के माध्यम से वर्चुअल विधि को कॉल करते हैं तो आप हमेशा वर्चुअल कॉल मैकेनिज्म को सक्रिय करते हैं जो सबसे व्युत्पन्न प्रकार पाता है।

आपकी सबसे अच्छी शर्त एक वैकल्पिक फ़ंक्शन जोड़ना है जो वर्चुअल नहीं है।

0

क्या फ़ंक्शन पॉइंटर के माध्यम से ऐसा करने का कोई विशिष्ट कारण है?

तुम सिर्फ लिखने के लिए सक्षम होना चाहिए:

Base::func(); 

आधार वर्ग कार्यान्वयन कॉल करने के लिए।

+1

जैसा कि मैंने अपने प्रश्न में लिखा था, मैं कॉलफनक में पॉइंटर को सहेजता हूं लेकिन वास्तव में अपने प्रोग्राम में किसी अन्य स्थान से func को कॉल करने के लिए इसका उपयोग करता हूं। –

+0

वर्चुअल फ़ंक्शन के लिए यह काम नहीं करेगा। यह हमेशा एक vtable लुकअप करेगा और व्युत्पन्न कक्षा पर विधि को कॉल करेगा। – Joel

1

आपकी समस्या यह है कि एक सदस्य फ़ंक्शन पॉइंटर एक नंगे फ़ंक्शन पॉइंटर के समान नहीं है। यह वास्तव में केवल एक सूचक नहीं है, लेकिन considerably more complex structure है, जो संकलक कार्यान्वयन के स्तर पर इसके विवरण में भिन्न होता है। जब आप इसे वाक्यविन्यास (this->*fp)() के माध्यम से आमंत्रित करते हैं तो आप वास्तव में इसे मूल ऑब्जेक्ट पर कॉल कर रहे हैं, जो वर्चुअल फ़ंक्शन प्रेषण का कारण बनता है।

एक चीज जो काम कर सकती है उसे गैर-विधि सूचक प्रकार पर डालना है। यह थोड़ा क्रैक है लेकिन मैं सोचता हूं यह काम करना चाहिए। आप अभी भी एक Base * उत्तीर्ण करने की आवश्यकता है, लेकिन आप यह स्पष्ट रूप से करते हैं और आभासी समारोह प्रेषण द्वारा पारित कर दिया है:

typedef void BasePointer(Base*); 

void callFunc() 
{ 
    BasePointer fp = (BasePointer *)&Base::func; 
    fp(this); 
} 

अद्यतन: ठीक है, नहीं, तुम इसे उस तरह से नहीं कर सकते। यह अवैध है, और अगर यह कानूनी था तो सुरक्षित नहीं होगा। C++ FAQ में more on this है। लेकिन यह जानकर कि आपकी समस्या का समाधान नहीं होता है। मुद्दा यह है कि, पॉइंटर के माध्यम से Base::func पर कॉल करने के लिए पॉइंटर-टू-ऑब्जेक्ट या पॉइंटर-टू-सदस्य, ऑब्जेक्ट यह इंगित कर रहा है कि भीBase हो। यदि आप इसे व्यवस्थित कर सकते हैं, तो आप एक सदस्य फ़ंक्शन पॉइंटर का उपयोग कर सकते हैं।

यहां एक और विचार है, सुंदर नहीं, लेकिन कम से कम काम करने योग्य। Derived में एक फ़ंक्शन प्रदान करें, गैर वर्चुअल, जो स्पष्ट रूप से Base::func पर कॉल करता है। इसके बजाय उस पर इंगित करें। यदि आपको func और callFunc के विभिन्न प्रकारों के सामान्य मामले में ऐसा करने की आवश्यकता है तो यह स्केल नहीं करेगा लेकिन यह एक विधि के लिए ठीक काम करेगा।

+1

वह निश्चित रूप से _not_ काम करेगा! 'Sizeof (बेसपोइंटर)' के साथ 'sizeof (& base :: func)' की तुलना करें: o –

+0

mmutz: Yup। मैं पोस्ट करने से पहले हमेशा परीक्षण करने की कोशिश करता हूं, और आज मैंने खुद को ऐसा करने का समय नहीं छोड़ा। यह * संभव * एक 'static_cast' सदस्य फ़ंक्शन पॉइंटर से फ़ंक्शन पॉइंटर भाग को पॉप करने के लिए पर्याप्त स्मार्ट हो सकता है, लेकिन मुझे डर है कि फ़ंक्शन की मेरी पायथन नोटियन अब मेरे सी ++ को ओवरराइड कर रही है :)। – quark

+0

यह गलत है: "इसमें केवल कॉल करने के लिए फ़ंक्शन का पता नहीं है बल्कि इसे" –

0

क्वार्क कहने के अलावा, एक और सामान्य टिप्पणी यह ​​है कि आपको एक नंगे फ़ंक्शन पॉइंटर के बजाय सिग्नल/स्लॉट कार्यान्वयन का उपयोग करना चाहिए। बूस्ट में एक है, libsigc और दूसरों का एक गुच्छा है।

2

दुर्भाग्य से आप क्या करने की कोशिश कर रहे हैं संभव नहीं है। पॉइंट-टू-सदस्य-फ़ंक्शन फ़ंक्शन की वर्चुअलनेस को बनाए रखने के लिए डिज़ाइन किए गए हैं।

0

इसमें क्या गलत है?

(Base(*this).*fp)(); 

अब अगर आप उस के साथ संतुष्ट हैं, तो यह कारण है कि आप भी पहली जगह में एक समारोह सूचक का उपयोग कर रहे का सवाल उठाती है। मुझे लगता है कि कुछ और संदर्भ मदद कर सकते हैं।

+0

यह पहले से ही क्वार्क द्वारा सुझाया गया था ("... यदि आप बेस पॉइंटर के माध्यम से बेस :: func को कॉल करना चाहते हैं, तो जिस ऑब्जेक्ट पर इशारा किया जा रहा है वह भी आधार होना चाहिए।")। मुझे लगता है कि एडी गारंटी नहीं दे सकता कि वह फ़ंक्शन को कॉल करते समय टुकड़ा करने के लिए प्रकार जानता है। – Troubadour