आप इन उत्तरों के साथ काल्पनिक रूप से प्राप्त कर रहे हैं, इसलिए मैं स्पष्टता के लिए पृथ्वी के स्पष्टीकरण के लिए और अधिक सरल बनाने की कोशिश करूंगा।
वस्तु उन्मुख डिजाइन के मूल संबंध दो हैं: आईएस-ए और एचएएस-ए। मैंने उन लोगों को नहीं बनाया। यही उन्हें कहा जाता है।
IS-A इंगित करता है कि किसी विशेष वस्तु की पहचान उस वर्ग के रूप में होती है जो उससे ऊपर श्रेणीबद्ध है। एक केला वस्तु एक फल वस्तु है यदि यह फल वर्ग का उपवर्ग है। इसका मतलब यह है कि कहीं भी एक फल वर्ग का उपयोग किया जा सकता है, एक केले का उपयोग किया जा सकता है। हालांकि यह रिफ्लेक्टिव नहीं है। आप किसी विशिष्ट वर्ग के लिए एक आधार वर्ग को स्थानापन्न नहीं कर सकते हैं यदि उस विशिष्ट वर्ग को बुलाया जाता है।
हैस ने संकेत दिया है कि एक वस्तु एक समग्र वर्ग का हिस्सा है और एक स्वामित्व संबंध है। C ++ में इसका मतलब यह है कि यह एक सदस्य वस्तु है और जैसे कि onus खुद को नष्ट करने से पहले इसे निपटाने या स्वामित्व को बंद करने के लिए मालिक वर्ग पर है।
इन दो अवधारणाओं को एकल वंशानुक्रम वाली भाषाओं में महसूस करना आसान है, जैसे कि एकाधिक विरासत मॉडल में c ++, लेकिन नियम अनिवार्य रूप से समान हैं। जटिलता तब आती है जब वर्ग की पहचान अस्पष्ट होती है, जैसे कि एक केले क्लास पॉइंटर को एक फंक्शन में पास करना जो फ्रूट क्लास पॉइंटर लेता है।
वर्चुअल फ़ंक्शंस, सबसे पहले, एक रन-टाइम चीज़ है। यह बहुरूपता का हिस्सा है कि इसका उपयोग यह तय करने के लिए किया जाता है कि चलने वाले कार्यक्रम में किस फ़ंक्शन को चलाना है।
वर्चुअल कीवर्ड एक कंपाइलर निर्देश है जो एक निश्चित क्रम में फ़ंक्शन को बाँधता है यदि वर्ग पहचान के बारे में अस्पष्टता है। वर्चुअल फ़ंक्शंस हमेशा पैरेंट क्लासेस में होते हैं (जहाँ तक मुझे पता है) और कंपाइलर को संकेत देते हैं कि अपने नाम से सदस्य फ़ंक्शंस की बाइंडिंग पहले सबक्लास फंक्शन और उसके बाद पेरेंट क्लास फंक्शन के साथ होनी चाहिए।
फ्रूट क्लास में वर्चुअल फ़ंक्शन रंग () हो सकता है जो डिफ़ॉल्ट रूप से "NONE" लौटाता है। केले वर्ग का रंग () फ़ंक्शन "YELLOW" या "BROWN" देता है।
लेकिन अगर फलों के पॉइंटर को लेने वाले फंक्शन में भेजे गए केले के वर्ग पर रंग () कॉल किया जाता है - कौन सा रंग () फंक्शन इनवैलिड हो जाता है? फल फल के लिए फंक्शन आमतौर पर फ्रूट :: कलर () कहलाता है।
99% उस समय नहीं होगा जो इरादा था। लेकिन अगर Fruit :: color () को वर्चुअल घोषित किया गया था तो Banana: color () को ऑब्जेक्ट के लिए कहा जाएगा क्योंकि कॉल के समय सही रंग () फ़ंक्शन फ्रूट पॉइंटर के लिए बाध्य होगा। रनटाइम यह जांच करेगा कि पॉइंटर पॉइंट किस ऑब्जेक्ट के कारण है क्योंकि यह फ्रूट क्लास की परिभाषा में वर्चुअल चिह्नित किया गया था।
यह एक उपवर्ग में एक फ़ंक्शन को ओवरराइड करने से अलग है। उस स्थिति में फ्रूट पॉइंटर फ्रूट :: कलर () कहेगा, अगर सभी को पता है कि यह फ्रूट का आईएस-ए पॉइंटर है।
तो अब एक "शुद्ध आभासी कार्य" का विचार आता है। यह बल्कि एक दुर्भाग्यपूर्ण वाक्यांश है क्योंकि शुद्धता का इससे कोई लेना-देना नहीं है। इसका अर्थ है कि यह उद्देश्य है कि बेस क्लास पद्धति को कभी नहीं बुलाया जाएगा। वास्तव में एक शुद्ध आभासी फ़ंक्शन को नहीं कहा जा सकता है। यह अभी भी परिभाषित किया जाना चाहिए। एक फ़ंक्शन हस्ताक्षर मौजूद होना चाहिए। कई कोडर पूर्णता के लिए एक खाली क्रियान्वयन {} करते हैं, लेकिन कंपाइलर आंतरिक रूप से उत्पन्न करेगा यदि नहीं। उस स्थिति में जब फ़ंक्शन को तब भी कहा जाता है, भले ही सूचक फल के लिए हो, केले :: रंग () कहा जाएगा क्योंकि यह रंग का एकमात्र कार्यान्वयन है () है।
अब पहेली का अंतिम टुकड़ा: निर्माता और विध्वंसक।
शुद्ध वर्चुअल कंस्ट्रक्टर अवैध हैं, पूरी तरह से। वह अभी बाहर है।
लेकिन शुद्ध वर्चुअल डिस्ट्रक्टर्स उस मामले में काम करते हैं, जिसे आप बेस क्लास इंस्टेंस के निर्माण से रोकना चाहते हैं। बेस क्लास का विध्वंसक शुद्ध आभासी होने पर ही सब क्लास को तत्काल किया जा सकता है। अधिवेशन इसे 0 पर असाइन करना है।
virtual ~Fruit() = 0; // pure virtual
Fruit::~Fruit(){} // destructor implementation
आपको इस मामले में एक कार्यान्वयन बनाना होगा। कंपाइलर जानता है कि यह आप क्या कर रहे हैं और सुनिश्चित करें कि आप इसे सही तरीके से करते हैं, या यह शिकायत करता है कि यह उन सभी कार्यों से लिंक नहीं कर सकता है जिन्हें इसे संकलित करने की आवश्यकता है। यदि आप अपने वर्ग पदानुक्रम की मॉडलिंग कैसे कर रहे हैं, तो त्रुटियां भ्रामक हो सकती हैं।
इसलिए आपको इस मामले में फल के उदाहरण बनाने से मना किया जाता है, लेकिन केले के उदाहरण बनाने की अनुमति है।
फ्रूट पॉइंटर को डिलीट करने के लिए एक कॉल जो केले के एक उदाहरण की ओर इशारा करता है, केले को बुलाएगा :: ~ केला () पहले और फिर फिएट :: ~ फ्रूट () को कॉल करें, हमेशा। क्योंकि कोई बात नहीं, जब आप एक उपवर्ग डिस्ट्रक्टर कहते हैं, तो बेस क्लास डिस्ट्रक्टर का पालन करना चाहिए।
क्या यह एक बुरा मॉडल है? यह डिजाइन चरण में अधिक जटिल है, हां, लेकिन यह सुनिश्चित कर सकता है कि रन-टाइम पर सही लिंकिंग की जाती है और एक उपवर्ग कार्य किया जाता है जहां अस्पष्टता होती है कि वास्तव में किस उपवर्ग तक पहुँचा जा रहा है।
यदि आप C ++ लिखते हैं, ताकि आप केवल सटीक क्लास पॉइंटर्स के साथ पास करें, जिसमें कोई सामान्य और अस्पष्ट बिंदु नहीं हैं, तो वर्चुअल फ़ंक्शन की वास्तव में आवश्यकता नहीं है। लेकिन अगर आपको प्रकार के रन-टाइम लचीलेपन की आवश्यकता होती है (जैसा कि Apple Banana Orange ==> Fruit) फ़ंक्शन कम निरर्थक कोड के साथ आसान और अधिक बहुमुखी हो जाते हैं। अब आपको प्रत्येक प्रकार के फलों के लिए एक फ़ंक्शन लिखना होगा, और आप जानते हैं कि प्रत्येक फल अपने सही फ़ंक्शन के साथ रंग () में जवाब देगा।
मुझे आशा है कि यह लंबे समय से व्याख्या स्पष्टीकरण भ्रमित करने वाली चीजों के बजाय अवधारणा को मजबूत करता है। वहाँ देखने के लिए बहुत सारे अच्छे उदाहरण हैं, और पर्याप्त रूप से देखें और वास्तव में उन्हें चलाएं और उनके साथ गड़बड़ करें और आप इसे प्राप्त करेंगे।