2017-07-27 54 views
8

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

#include <iostream> 

using namespace std; 
class Base{ 
public: 
    void printMe(){ 
     cout << "I am the base" << endl; 
    } 
}; 
class Derived: public Base{ 
public: 
    void printMe(){ 
     cout << "I am the derived" << endl; 
    } 
}; 
int main() { 
    Base a; 
    Derived b; 
    a.printMe(); 
    b.printMe(); 
    return 0; 
} 
+2

नोट: 'नेमस्पेस std का उपयोग करना;' में शामिल होने की एक बुरी आदत है और यदि आप अभी रोक सकते हैं तो आप भविष्य में पूरे सिरदर्द से बच सकते हैं। 'Std ::' उपसर्ग एक कारण के लिए है: यह आपके स्वयं के वर्गों, संरचनाओं और चर के साथ संघर्ष से बचाता है। – tadman

+3

'बेस * पी = नया व्युत्पन्न; पी-> printMe(); 'वर्चुअल' के साथ और बिना। – HolyBlackCat

+7

स्पष्टीकरण के लिए - एक पॉइंटर या उसके बेस क्लास के संदर्भ के माध्यम से ऑब्जेक्ट तक पहुंचने पर पॉलीमोर्फिक व्यवहार प्राप्त किया जाता है। – DeiDei

उत्तर

11

निम्नलिखित उदाहरण पर विचार करें। virtual और override की आवश्यकता को चित्रित करने के लिए महत्वपूर्ण पंक्ति c->printMe(); है। ध्यान दें कि c का प्रकार Base* है, हालांकि पॉलिमॉर्फिज्म के कारण यह व्युत्पन्न वर्ग से ओवरराइड विधि को कॉल करने में सही ढंग से सक्षम है।

#include <iostream> 

class Base{ 
public: 
    virtual void printMe(){ 
     std::cout << "I am the base" << std::endl; 
    } 
}; 

class Derived: public Base{ 
public: 
    void printMe() override { 
     std::cout << "I am the derived" << std::endl; 
    } 
}; 

int main() { 
    Base a; 
    Derived b; 
    a.printMe(); 
    b.printMe(); 
    Base* c = &b; 
    c->printMe(); 
    return 0; 
} 

उत्पादन

I am the base 
I am the derived 
I am the derived 
+3

हालांकि, आपने समझाया नहीं है कि 'ओवरराइड' कीवर्ड का उद्देश्य क्या है। –

+0

मैंने किया (केवल मुझे), लेकिन लोग पहले जवाब पर मतदान करते हैं जो वे देखते हैं। –

2

आप यहाँ व्यवहार नहीं देख रहे हैं क्योंकि आप b घोषित किया है प्रकार Derived तो संकलक जानता कार्यों क्या उपयोग करने के लिए की हो।

int main() { 
    Base a; 
    Base *b = new Derived(); 

    a.printMe(); 
    b->printMe(); 

    delete b; 

    return 0; 
} 

अब b प्रकार Base* यह आभासी समारोह तालिका में Base प्लस जो कुछ भी की पर कार्यों का उपयोग करने के लिए जा रहा है, जिसका मतलब है की है: आदेश बेनकाब करने के लिए क्यों virtual आवश्यक है आप चीजों को मिश्रण करने की जरूरत है। यह आपके कार्यान्वयन को तोड़ देता है। आप virtual चीजों को ठीक से घोषित करके इसे ठीक कर सकते हैं।

+0

क्या आप लाइन 3 पर नए कीवर्ड के उपयोग को समझाने में सक्षम होंगे? मैं इस संदर्भ में नए कामों पर थोड़ा सा जंगली हूं। मुझे पता है कि आप टाइप बेस का सूचक बना रहे हैं; तो क्या आप व्युत्पन्न कक्षा को पकड़ने के लिए पर्याप्त स्मृति आवंटित कर रहे हैं? लाइन 3 कैसे काम करता है? –

+0

यह 'नया' का उपयोग कर सीधी सी ++ आवंटन है। यह सी के 'मॉलोक' की तरह है लेकिन अधिक खुफिया अंतर्निहित है, साथ ही यह स्वचालित रूप से प्रारंभकर्ता को कॉल करता है। एक अच्छी सी ++ संदर्भ पुस्तक में 'नई' और 'हटाएं' की मूल बातें शामिल होनी चाहिए। यदि आपके पास कोई नहीं है, तो [सी ++ के लेखक द्वारा) [http://www.stroustrup.com/4th.html) शुरू करने के लिए एक अच्छी जगह है। – tadman

+1

@tadman: जैसा कि मैंने दूसरे जवाब पर टिप्पणी की है, मुझे लगता है कि हम नए 'नए' और 'डिलीट' का उपयोग न करने के लिए बेहतर हैं, उदाहरण के लिए नवागंतुकों के लिए कोड, क्योंकि उन्हें आम तौर पर आधुनिक सी ++ में खराब अभ्यास के रूप में देखा जाता है। एक संदर्भ (या 'बी = और ए') बिंदु भी बना देगा। –

6
कोड आप के साथ

, अगर आप ऐसा करते हैं

Derived derived; 
Base* base_ptr = &derived; 
base_ptr->printMe(); 

आपको क्या लगता है होता हैं? यह I am the derived प्रिंट नहीं करेगा क्योंकि विधि वर्चुअल नहीं है, और प्रेषण कॉलिंग ऑब्जेक्ट के स्थिर प्रकार (यानी Base) से प्रेषित किया जाता है। यदि आप इसे आभासी में बदलते हैं तो जिसे विधि कहा जाता है वह वस्तु के गतिशील प्रकार पर निर्भर करेगा, न कि स्थिर प्रकार।

2

override एक नया कीवर्ड सी ++ 11 में जोड़ा है। अगर एक आधार वर्ग एक मेल virtual विधि शामिल

  • संकलक की जाँच करेगा:

    आप क्योंकि यह प्रयोग करना चाहिए। यह महत्वपूर्ण है क्योंकि विधि नाम में कुछ टाइपो या तर्कों की सूची में (अधिभार की अनुमति है) इंप्रेशन का कारण बन सकती है कि वास्तव में कुछ नहीं होने पर कुछ ओवरराइड किया गया था।

  • यदि आप एक विधि के लिए override का उपयोग करते हैं, तो संकलक override कीवर्ड का उपयोग किए बिना किसी अन्य विधि को ओवरराइड किया गया है, तो एक त्रुटि रिपोर्ट करेगा। प्रतीक टकराव होने पर यह अवांछित ओवरराइड का पता लगाने में मदद करता है।

  • virtual का मतलब "ओवरराइड" नहीं है। कक्षा में एक विधि को ओवरराइड करने के बजाय "ओवरराइड" कीवर्ड का उपयोग करें, आप "वर्चुअल" कीवर्ड को छोड़कर इस विधि को आसानी से लिख सकते हैं, ओवरराइड पूरी तरह से घटित होगा।डेवलपर्स ओवरराइड के इरादे को इंगित करने के लिए सी ++ 11 से पहले virtual लिख रहे थे। बस virtual का अर्थ है: इस विधि को सबक्लास में ओवरराइड किया जा सकता है।

+0

"वर्चुअल का मतलब" ओवरराइड "नहीं है। अगर आप इसे छोड़ देते हैं, ओवरराइडिंग अभी भी काम करेगा।" मुझे लगता है कि अगर आप इसे व्युत्पन्न कक्षाओं में छोड़ देते हैं तो यह मतलब नहीं है कि यदि आप बेस – ROX

+0

आधार पर छोड़ देते हैं, तो मेरा यही मतलब है। मैंने टेक्स्ट को और स्पष्ट करने के लिए बेहतर किया है। –

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