वर्चुअल फंक्शन

From alpha
Jump to navigation Jump to search

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

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

उद्देश्य

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

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

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

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

उदाहरण

सी ++

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

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

class Animal {
 public:
  // Intentionally not virtual:
  void Move() {
    std::cout << "This animal moves in some way" << std::endl;
  }
  virtual void Eat() = 0;
};

// The class "Animal" may possess a definition for Eat if desired.
class Llama : public Animal {
 public:
  // The non virtual function Move is inherited but not overridden.
  void Eat() override {
    std::cout << "Llamas eat grass!" << std::endl;
  }
};

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

C में, वर्चुअल फंक्शन्सों के पीछे का तंत्र निम्नलिखित तरीके से प्रदान किया जा सकता है:

#include <stdio.h>

/* an object points to its class... */
struct Animal {
    const struct AnimalClass * class;
};

/* which contains the virtual function Animal.Eat */
struct AnimalClass {
    void (*Eat)(struct Animal *); // 'virtual' function 
};

/* Since Animal.Move is not a virtual function
   it is not in the structure above. */
void Move(struct Animal * self)
{
    printf("<Animal at %p> moved in some way\n", (void *) self);
}

/* unlike Move, which executes Animal.Move directly,
   Eat cannot know which function (if any) to call at compile time.
   Animal.Eat can only be resolved at run time when Eat is called. */
void Eat(struct Animal * self)
{
    const struct AnimalClass * class = *(const void **) self;
    if (class->Eat) 
        class->Eat(self); // execute Animal.Eat
    else
        fprintf(stderr, "Eat not implemented\n");
}

/* implementation of Llama.Eat this is the target function 
   to be called by 'void Eat(struct Animal *).' */
static void _Llama_eat(struct Animal * self)
{
    printf("<Llama at %p> Llama's eat grass!\n", (void *) self);    
}

/* initialize class */
const struct AnimalClass Animal = {(void *) 0}; // base class does not implement Animal.Eat
const struct AnimalClass Llama = {_Llama_eat};  // but the derived class does

int main(void)
{
   /* init objects as instance of its class */
   struct Animal animal = {& Animal};
   struct Animal llama = {& Llama};
   Move(& animal); // Animal.Move
   Move(& llama);  // Llama.Move
   Eat(& animal);  // cannot resolve Animal.Eat so print "Not Implemented" to stderr
   Eat(& llama);   // resolves Llama.Eat and executes
}

एब्स्ट्रैक्ट क्लासेज और शुद्ध वर्चुअल फंक्शन्स

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

एक उदाहरण के रूप में, एक एब्स्ट्रैक्ट आधार क्लासेज 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".