2012-01-26 28 views
10

मेरे पास एक क्लास टेम्पलेट है जहां कुछ विधियों को वर्चुअल के रूप में परिभाषित किया जाता है ताकि वे मेरी कक्षा के उपयोगकर्ता को उनके व्युत्पन्न वर्ग में कार्यान्वयन कर सकें। ध्यान दें कि मेरे टेम्पलेट वर्ग में कुछ गैर-आभासी विधियां हैं जो वर्चुअल एक का उपयोग करती हैं (एक वर्चुअल क्लास जिसे मान वापस करना चाहिए गैर-आभासी वर्ग में कहा जाता है)।सी ++ आभासी विधि ओवरराइड

क्या आप मुझे एक सही कोड का एक सरल उदाहरण दे सकते हैं जहां मूल वर्ग की आभासी विधि को एक मूल्य वापस करना चाहिए (लेकिन यह कार्यान्वयन बाल वर्ग में प्रदान किया जाता है) और मूल वर्ग में वर्चुअल विधि द्वारा लौटाया गया मान उस वर्ग के अन्य तरीकों में प्रयोग किया जाता है। क्योंकि मैंने कहीं देखा (उदाहरण के लिए यहां: Safely override C++ virtual functions) इससे कुछ समस्याएं हो सकती हैं और उपयोगकर्ता परिभाषित विधि अभिभावक वर्ग की वर्चुअल विधि को ओवरराइड कर देगी।

नोट: मैं g ++ कंपाइलर का उपयोग कर कोड :: ब्लॉक के साथ प्रोग्राम।

संपादित करें:)

template<typename T> 
class parent { 
public: 
    // Public methods that user can call 
    int getSomething(T t); 
    void putSomething(T t, int x); 

    // public method that user should implement in his code 
    virtual float compute(T t) { } 

    // protected or private methods and attributes used internally by putSomething ... 
    float doComplexeThings(...); // this can call 
}; 

विधि गणना (उपयोगकर्ता (बच्चे वर्ग) द्वारा लागू किया जाना चाहिए: यहाँ मैं क्या चाहते का एक सरल उदाहरण अनुरोध किया। हालांकि, उदाहरण के लिए putSomething() और doComplexeThings() द्वारा इस विधि गणना() को बुलाया जाता है।

+0

जो आप वर्णन करते हैं, उसके लिए वर्चुअल विधि की आवश्यकता नहीं हो सकती है (स्थैतिक बहुरूपता आपके लिए काम कर सकती है) - आपके विवरण से बताना मुश्किल है। कृपया आपके द्वारा लिखे गए नमूना कोड को पोस्ट करें ताकि हमारे पास वास्तव में एक बेहतर अर्थ हो जो आप करने की कोशिश कर रहे हैं। – kfmfe04

+0

लिंक किए गए प्रश्न में उदाहरण एक ओवरराइड है जो आपको लगता है कि वास्तव में एक त्रुटि के कारण अधिभार घोषित करता है, उदाहरण के लिए एक कॉन्स गायब है और वापसी मूल्यों के बारे में नहीं था। आपको क्या लगता है खतरे है, बिल्कुल? – CashCow

+0

क्लासिक टेम्पलेट कोड में, आपको 'वर्चुअल फ्लोट कंप्यूट (टी टी)' घोषित करने की भी आवश्यकता नहीं है। यदि आप उदाहरण के लिए हैंडल करते हैं, तो आप इसे 't.compute()' के माध्यम से putSomething() और doComplexeThings() के अंदर बस (इसे कॉल करें) का उपयोग करें। यदि आपकी कक्षा टी गणना लागू नहीं करती है तो संकलक त्रुटि देगा। इस तरह, माता-पिता और टी को वास्तव में एक ही विरासत पदानुक्रम में भी रहना नहीं पड़ता है: यानी, टी माता-पिता के रिश्ते का एक बच्चा आवश्यक नहीं है। ऐसा करने से आपको माता-पिता को एक और सार्थक नाम देने का मौका मिल सकता है (क्योंकि यह संबंध आवश्यक नहीं है)। – kfmfe04

उत्तर

18

आपको बस यह सुनिश्चित करना होगा कि विधियों के समान हस्ताक्षर (कॉन्स/म्यूटेबल संशोधक और तर्क प्रकार सहित) हैं। यदि आप सबक्लास में फ़ंक्शन को ओवरराइड करने में विफल रहते हैं तो आप संकलक त्रुटियों को उत्तेजित करने के लिए शुद्ध वर्चुअल परिभाषा का उपयोग कर सकते हैं।

float compute() override; 

एक व्युत्पन्न वर्ग में उपरोक्त पंक्ति एक संकलक का कारण होगा:

class parent { 
public: 
    // pure virtual method must be provided in subclass 
    virtual void handle_event(int something) = 0; 
}; 

class child : public parent { 
public: 
    virtual void handle_event(int something) { 
    // new exciting code 
    } 
}; 

class incomplete_child : public parent { 
public: 
    virtual void handle_event(int something) const { 
    // does not override the pure virtual method 
    } 
}; 

int main() { 
    parent *p = new child(); 
    p->handle_event(1); // will call child::handle_event 
    parent *p = new incomplete_child(); // will not compile because handle_event 
             // was not correctly overridden 
} 
+0

* वर्चुअल विधियों के लिए कॉन्वेंट रिटर्न प्रकार * की अनुमति है। –

+3

@als, '* covariant वापसी प्रकारों को अनुमति देने के लिए बस एक छोटा सा विवरण * की अनुमति है *, कॉन्वेंट प्रकारों को केवल तभी अनुमति दी जाती है जब फ़ंक्शन कोई संदर्भ या सूचक देता है। मुझे पता है कि आप यह जानते हैं, लेकिन मैं दूसरों के लिए यह टिप्पणी छोड़ रहा हूं। –

+2

@mschneider आपके उत्तर में समस्या यह है कि आप किसी संभावित समस्या से बचने के लिए अर्थशास्त्र में बदलाव को मजबूर कर रहे हैं। मूल मामले में फ़ंक्शन मौजूद था लेकिन आपके प्रस्तावित समाधान में इसे अधिभारित किया जा सकता था, इसे * ओवरलोड किया जाना चाहिए। यह किसी मौजूदा फ़ंक्शन को ओवरलोड करते समय त्रुटियों से निपटता नहीं है, बल्कि * बलों * व्युत्पन्न कक्षाओं को ओवरलोड करने के लिए नहीं करता है। एक दिलचस्प C++ 11 सुविधा के लिए –

20

आप अपने संकलक में सी ++ 11 सुविधाओं का उपयोग कर सकते हैं तो ओवरराइड करता है override विशेष पहचानकर्ता के साथ इतनी के रूप में चिह्नित किया जा सकता है त्रुटि के रूप में फ़ंक्शन आधार में किसी सदस्य फ़ंक्शन को ओवरराइड नहीं करता है (गलत हस्ताक्षर, अनुपलब्ध तर्क)। लेकिन ध्यान दें कि यह प्रत्येक व्युत्पन्न वर्ग में किया जाना चाहिए, यह एक समाधान नहीं है जिसे आप बेस क्लास से लगा सकते हैं।

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

+0

+1 - यह सुनिश्चित करने के लिए सहायक है कि आपकी विधि वास्तव में कुछ ओवरराइड कर रही है – kfmfe04

0

यह प्रश्न 2013 में पूछा गया है। यह बहुत पुराना है लेकिन मुझे कुछ नया मिला जो उत्तर में मौजूद नहीं है।

हम तीन अवधारणा को समझने की जरूरत है अधिभार, के ऊपर लिख, और छिपाने है।

संक्षिप्त उत्तर, आप बेस क्लास से विरासत समारोह को अधिभारित करना चाहते हैं। हालांकि, अधिभार फ़ंक्शन के लिए कई व्यवहार जोड़ने के लिए तंत्र है जिसे इन सभी कार्यों को एक ही पैमाने पर आवश्यक है। लेकिन वर्चुअल फ़ंक्शन बेस क्लास में स्पष्ट रूप से है।

class A { 
public: 
    virtual void print() { 
    cout << id_ << std::endl; 
    } 
private: 
    string id_ = "A"; 
}; 

class B : A { 
public: 
    using A::print; 
    void print(string id) { 
    std::cout << id << std::endl; 
    } 
}; 

int main(int argc, char const *argv[]) { 
    /* code */ 
    A a; 
    a.print(); 
    B b; 
    b.print(); 
    b.print("B"); 
    return 0; 
} 

का उपयोग कर एक :: प्रिंट जोड़ें; आपके व्युत्पन्न वर्ग में काम करेगा!

हालांकि मैं यह एक अच्छा विचार है के बाद से अधिभार और विरासत पीछे दर्शन अलग है नहीं लग रहा है, यह नहीं हो सकता उन्हें एक साथ घोंसला करने के लिए एक अच्छा विचार है।

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