वर्चुअल फंक्शन: Difference between revisions

From Vigyanwiki
No edit summary
No edit summary
Line 5: Line 5:


== उद्देश्य ==
== उद्देश्य ==
{{further|Dynamic dispatch}}
{{further|गतिशील प्रेषण}}
वर्चुअल फ़ंक्शन की अवधारणा निम्न समस्या हल करती है:
वर्चुअल फ़ंक्शन की अवधारणा निम्न समस्या हल करती है:



Revision as of 11:07, 18 February 2023

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

अधिकांश प्रोग्रामिंग लैंग्वेज, जैसे कि जावास्क्रिप्ट, पीएचपी और पायथन (प्रोग्रामिंग लैंग्वेज), डिफ़ॉल्ट रूप से सभी तरीकों को वर्चुअल मानते हैं[1][2] और इस व्यवहार को बदलने के लिए संशोधक प्रदान न करें। हालाँकि, कुछ भाषाएँ संशोधक प्रदान करती हैं ताकि विधियों को व्युत्पन्न कक्षाओं द्वारा ओवरराइड होने से रोका जा सके (जैसे कि जावा में अंतिम कीवर्ड (प्रोग्रामिंग भाषा)[3] और पीएचपी[4]).

उद्देश्य

वर्चुअल फ़ंक्शन की अवधारणा निम्न समस्या हल करती है:

ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग में, जब एक व्युत्पन्न वर्ग बेस क्लास से विरासत में मिलता है, तो व्युत्पन्न वर्ग का एक ऑब्जेक्ट व्युत्पन्न वर्ग प्रकार के बजाय बेस क्लास प्रकार के पॉइंटर (कंप्यूटर प्रोग्रामिंग) या संदर्भ (कंप्यूटर विज्ञान) के माध्यम से संदर्भित किया जा सकता है। . यदि व्युत्पन्न वर्ग द्वारा ओवरराइड किए गए आधार वर्ग के तरीके हैं, तो वास्तव में इस तरह के संदर्भ या सूचक द्वारा बुलाए गए तरीके को सूचक या संदर्भ के घोषित प्रकार के अनुसार, 'प्रारंभिक' (संकलक द्वारा) बाध्य (लिंक) किया जा सकता है, या 'लेट' (अर्थात् भाषा के रनटाइम सिस्टम द्वारा), वस्तु के वास्तविक प्रकार के अनुसार संदर्भित किया जाता है।

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

वर्चुअल फ़ंक्शंस प्रोग्राम को उन विधियों को कॉल करने की अनुमति देते हैं जो कोड संकलित होने के समय जरूरी नहीं हैं।[citation needed] C++ में, आभासी विधियों को जोड़कर घोषित किया जाता है virtual बेस क्लास में फ़ंक्शन की घोषणा के लिए कीवर्ड। यह संशोधक व्युत्पन्न कक्षाओं में उस पद्धति के सभी कार्यान्वयनों द्वारा विरासत में मिला है, जिसका अर्थ है कि वे एक-दूसरे को ओवर-राइड करना जारी रख सकते हैं और लेट-बाउंड हो सकते हैं। और यहां तक ​​​​कि अगर बेस क्लास के स्वामित्व वाली विधियां वर्चुअल विधि को कॉल करती हैं, तो वे इसके बजाय व्युत्पन्न विधि को कॉल करेंगे। ओवरलोडिंग तब होती है जब एक वर्ग में दो या दो से अधिक विधियों का एक ही विधि नाम होता है लेकिन अलग-अलग पैरामीटर होते हैं। ओवरराइडिंग का अर्थ है एक ही विधि नाम और मापदंडों के साथ दो विधियाँ होना। ओवरलोडिंग को फंक्शन मैचिंग और ओवरराइडिंग को डायनामिक फंक्शन मैपिंग भी कहा जाता है।

उदाहरण

सी ++

जानवरों का वर्ग आरेख

उदाहरण के लिए, एक आधार वर्ग Animal वर्चुअल फ़ंक्शन हो सकता है Eat. उपवर्ग Llama लागू करेगा Eat उपवर्ग से अलग Wolf, लेकिन कोई आह्वान कर सकता है Eat पशु के रूप में संदर्भित किसी भी वर्ग के उदाहरण पर, और प्राप्त करें Eat विशिष्ट उपवर्ग का व्यवहार।

<वाक्यविन्यास लैंग = सीपीपी> वर्ग पशु {

जनता:
 // जानबूझकर आभासी नहीं:
 शून्य चाल () {
 std::cout << यह जानवर किसी तरह चलता है << std::endl;
 }
 आभासी शून्य खाओ () = 0;

};

// क्लास एनिमल के पास इच्छा होने पर खाने की परिभाषा हो सकती है। वर्ग लामा : सार्वजनिक पशु {

जनता:
 // नॉन वर्चुअल फंक्शन मूव विरासत में मिला है लेकिन ओवरराइड नहीं हुआ है।
 शून्य खाओ () ओवरराइड {
 std::cout << लामा घास खाते हैं! << एसटीडी�:: एंडल;
 }

}; </वाक्यविन्यास हाइलाइट>

यह एक प्रोग्रामर को क्लास के ऑब्जेक्ट्स की सूची को प्रोसेस करने की अनुमति देता है Animalप्रत्येक को बारी-बारी से खाने के लिए कहना (कॉल करके)। Eat), यह जानने की आवश्यकता के बिना कि सूची में किस प्रकार का जानवर हो सकता है, प्रत्येक जानवर कैसे खाता है, या संभावित प्रकार के जानवरों का पूरा सेट क्या हो सकता है।

सी में, आभासी कार्यों के पीछे का तंत्र निम्नलिखित तरीके से प्रदान किया जा सकता है: <वाक्यविन्यास प्रकाश लैंग = सी>

  1. शामिल <stdio.h>

/* वस्तु अपनी कक्षा की ओर इशारा करती है... */ संरचना पशु {

 कास्ट स्ट्रक्चर एनिमलक्लास * क्लास;

};

/* जिसमें वर्चुअल फंक्शन एनिमल.ईट होता है */ संरचना पशु वर्ग {

 शून्य (* खाओ) (संरचना पशु *); // 'वर्चुअल' फंक्शन

};

/* चूँकि Animal.Move एक वर्चुअल फंक्शन नहीं है

 यह ऊपर की संरचना में नहीं है। */

शून्य मूव (स्ट्रक्चर एनिमल * सेल्फ) {

 प्रिंटफ ( <%p पर पशु> किसी तरह से स्थानांतरित \n, (शून्य *) स्वयं);

}

/* मूव के विपरीत, जो एनिमल को निष्पादित करता है। सीधे मूव करें,

 खाओ संकलन समय पर कॉल करने के लिए कौन सा फ़ंक्शन (यदि कोई हो) नहीं जान सकता है।
 एनिमल.ईट को केवल रन टाइम पर हल किया जा सकता है जब ईट को कॉल किया जाता है। */

शून्य खाओ (संरचना पशु * स्वयं) {

 कास्ट स्ट्रक्चर एनिमलक्लास * क्लास = * (कास्ट शून्य **) स्वयं;
 अगर (वर्ग-> खाओ)
 वर्ग-> खाओ (स्वयं); // एनिमल को निष्पादित करें। खाओ
 अन्य
 fprintf(stderr, ईट नॉट इम्प्लीमेंटेड\n);

}

/* लामा का कार्यान्वयन। यह लक्ष्य कार्य है

 'शून्य खाओ (संरचना पशु *)' द्वारा बुलाया जाना। */

स्थैतिक शून्य _लामा_ईट (संरचना पशु * स्वयं) {

 प्रिंटफ (<लामा %p पर> लामा घास खाते हैं!\n, (शून्य *) स्वयं);

}

/* क्लास इनिशियलाइज़ करें */ कास्ट स्ट्रक्चर एनिमलक्लास एनिमल = {(शून्य *) 0}; // बेस क्लास एनिमल.ईट को लागू नहीं करता है const स्ट्रक्चर एनिमलक्लास लामा = {_Llama_eat}; // लेकिन व्युत्पन्न वर्ग करता है

पूर्णांक मुख्य (शून्य) {

 / * अपनी कक्षा के उदाहरण के रूप में init ऑब्जेक्ट * /
 संरचना पशु पशु = {& पशु};
 संरचना पशु लामा = {& लामा};
 हटो (और जानवर); // पशु। हटो
 हटो (और लामा); // लामा। हटो
 खाओ (और जानवर); // एनिमल को हल नहीं कर सकता। इसलिए प्रिंट करें, इसे लागू नहीं किया गया
 खाओ (और लामा); // लामा को हल करता है। खाओ और निष्पादित करो

} </वाक्यविन्यास हाइलाइट>

सार वर्ग और शुद्ध आभासी कार्य

एक शुद्ध वर्चुअल फ़ंक्शन या शुद्ध वर्चुअल विधि एक वर्चुअल फ़ंक्शन है जिसे व्युत्पन्न वर्ग द्वारा लागू किया जाना आवश्यक है यदि व्युत्पन्न वर्ग सार प्रकार नहीं है। शुद्ध आभासी विधियों वाली कक्षाओं को सार कहा जाता है और उन्हें सीधे तत्काल नहीं किया जा सकता है। एक सार वर्ग का एक उपवर्ग (कंप्यूटर विज्ञान) केवल सीधे ही तत्काल किया जा सकता है यदि सभी विरासत में मिली शुद्ध आभासी विधियों को उस वर्ग या मूल वर्ग द्वारा लागू किया गया हो। शुद्ध आभासी तरीकों में आमतौर पर एक घोषणा (प्रकार हस्ताक्षर # विधि हस्ताक्षर) होती है और कोई परिभाषा नहीं होती है (विधि कार्यान्वयन)।

एक उदाहरण के रूप में, एक सार आधार वर्ग MathSymbol एक शुद्ध आभासी कार्य प्रदान कर सकता है doOperation(), और व्युत्पन्न वर्ग Plus और Minus अमल में लाना doOperation() ठोस कार्यान्वयन प्रदान करने के लिए। क्रियान्वयन doOperation() में कोई मतलब नहीं होगा MathSymbol वर्ग, के रूप में MathSymbol एक अमूर्त अवधारणा है जिसका व्यवहार केवल प्रत्येक दिए गए प्रकार (उपवर्ग) के लिए परिभाषित किया गया है MathSymbol. इसी तरह, एक दिया गया उपवर्ग MathSymbol के कार्यान्वयन के बिना पूरा नहीं होगा doOperation().

हालाँकि शुद्ध आभासी विधियों का आमतौर पर उस वर्ग में कोई कार्यान्वयन नहीं होता है जो उन्हें घोषित करता है, कुछ भाषाओं में शुद्ध आभासी विधियों (जैसे C ++ और पायथन) को उनके घोषित वर्ग में कार्यान्वयन शामिल करने की अनुमति है, फ़ॉलबैक या डिफ़ॉल्ट व्यवहार प्रदान करता है जिसे एक व्युत्पन्न वर्ग प्रतिनिधि कर सकता है। , अगर उचित है।[5][6] शुद्ध आभासी कार्यों का भी उपयोग किया जा सकता है जहां इंटरफ़ेस (जावा) को परिभाषित करने के लिए विधि घोषणाओं का उपयोग किया जा रहा है - जैसा कि जावा में इंटरफ़ेस कीवर्ड स्पष्ट रूप से निर्दिष्ट करता है। ऐसे उपयोग में, व्युत्पन्न वर्ग सभी कार्यान्वयनों की आपूर्ति करेगा। इस तरह के एक डिज़ाइन पैटर्न में, इंटरफ़ेस के रूप में कार्य करने वाले सार वर्ग में केवल शुद्ध आभासी कार्य होंगे, लेकिन कोई डेटा सदस्य या साधारण तरीके नहीं होंगे। सी ++ में, इंटरफेस के रूप में ऐसे पूरी तरह से सार वर्गों का उपयोग करना काम करता है क्योंकि सी ++ एकाधिक विरासत का समर्थन करता है। हालाँकि, क्योंकि कई OOP भाषाएँ एकाधिक वंशानुक्रम का समर्थन नहीं करती हैं, वे अक्सर एक अलग इंटरफ़ेस तंत्र प्रदान करते हैं। एक उदाहरण जावा (प्रोग्रामिंग भाषा) है।

निर्माण और विनाश के दौरान व्यवहार

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

सी ++ में, बेस फ़ंक्शन कहा जाता है। विशेष रूप से, सबसे अधिक व्युत्पन्न कार्य जो वर्तमान निर्माता या विध्वंसक वर्ग से अधिक व्युत्पन्न नहीं है, कहलाता है।[7]: §15.7.3 [8][9] यदि वह कार्य एक शुद्ध आभासी कार्य है, तो अपरिभाषित व्यवहार होता है।[7]: §13.4.6 [8]यह सच है भले ही कक्षा में उस शुद्ध वर्चुअल फ़ंक्शन के लिए कार्यान्वयन हो, क्योंकि शुद्ध वर्चुअल फ़ंक्शन के लिए कॉल स्पष्ट रूप से योग्य होना चाहिए।[10] संकलन समय या लिंक समय पर शुद्ध आभासी कार्यों के लिए अप्रत्यक्ष कॉल का पता लगाने के लिए एक अनुरूप सी ++ कार्यान्वयन की आवश्यकता नहीं है (और आमतौर पर सक्षम नहीं)। रनटाइम (प्रोग्राम लाइफसाइकिल चरण) पर शुद्ध वर्चुअल फ़ंक्शन के लिए कॉल का सामना करते समय कुछ रनटाइम सिस्टम शुद्ध वर्चुअल फ़ंक्शन कॉल त्रुटि जारी करेंगे।

जावा और सी # में, व्युत्पन्न कार्यान्वयन कहा जाता है, लेकिन कुछ क्षेत्रों को अभी तक व्युत्पन्न कन्स्ट्रक्टर द्वारा प्रारंभ नहीं किया गया है (हालांकि वे अपने डिफ़ॉल्ट शून्य मानों में प्रारंभ किए गए हैं)।[11] कुछ डिज़ाइन पैटर्न (कंप्यूटर विज्ञान), जैसे सार फैक्टरी पैटर्न, इस क्षमता का समर्थन करने वाली भाषाओं में सक्रिय रूप से इस उपयोग को बढ़ावा देते हैं।

आभासी विनाशक

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

मैन्युअल स्मृति प्रबंधन संदर्भों में, स्थिति अधिक जटिल हो सकती है, विशेष रूप से स्थैतिक प्रेषण के संबंध में। यदि वुल्फ प्रकार का एक ऑब्जेक्ट बनाया गया है, लेकिन एक एनिमल पॉइंटर द्वारा इंगित किया गया है, और यह एनिमल पॉइंटर प्रकार है जिसे हटा दिया गया है, तो कहा जाने वाला विध्वंसक वास्तव में एनिमल के लिए परिभाषित हो सकता है और वुल्फ के लिए नहीं, जब तक कि विध्वंसक आभासी न हो . यह विशेष रूप से सी ++ के मामले में है, जहां विनाशक आभासी नहीं होने पर व्यवहार प्रोग्रामिंग त्रुटियों का एक आम स्रोत है।

यह भी देखें

संदर्भ

  1. "Polymorphism (The Java™ Tutorials > Learning the Java Language > Interfaces and Inheritance)". docs.oracle.com. Retrieved 2020-07-11.
  2. "9. Classes — Python 3.9.2 documentation". docs.python.org. Retrieved 2021-02-23.
  3. "Writing Final Classes and Methods (The Java™ Tutorials > Learning the Java Language > Interfaces and Inheritance)". docs.oracle.com. Retrieved 2020-07-11.
  4. "PHP: Final Keyword - Manual". www.php.net. Retrieved 2020-07-11.
  5. Pure virtual destructors - cppreference.com
  6. "abc — Abstract Base Classes: @abc.abstractmethod"
  7. 7.0 7.1 "N4659: Working Draft, Standard for Programming Language C++" (PDF).
  8. 8.0 8.1 Chen, Raymond (April 28, 2004). "What is __purecall?".
  9. Meyers, Scott (June 6, 2005). "Never Call Virtual Functions during Construction or Destruction".
  10. Chen, Raymond (October 11, 2013). "C++ corner case: You can implement pure virtual functions in the base class".
  11. Ganesh, S.G. (August 1, 2011). "Joy of Programming: Calling Virtual Functions from Constructors".