वर्चुअल फंक्शन: Difference between revisions
No edit summary |
(→सी ++) |
||
Line 20: | Line 20: | ||
[[Image:ClassDiagram for VirtualFunction.png|400px|thumb|right|जानवरों का वर्ग आरेख]]उदाहरण के लिए, एक आधार वर्ग <code>Animal</code> वर्चुअल फ़ंक्शन हो सकता है <code>Eat</code>. उपवर्ग <code>Llama</code> लागू करेगा <code>Eat</code> उपवर्ग से अलग <code>Wolf</code>, लेकिन कोई आह्वान कर सकता है <code>Eat</code> पशु के रूप में संदर्भित किसी भी वर्ग के उदाहरण पर, और प्राप्त करें <code>Eat</code> विशिष्ट उपवर्ग का व्यवहार। | [[Image:ClassDiagram for VirtualFunction.png|400px|thumb|right|जानवरों का वर्ग आरेख]]उदाहरण के लिए, एक आधार वर्ग <code>Animal</code> वर्चुअल फ़ंक्शन हो सकता है <code>Eat</code>. उपवर्ग <code>Llama</code> लागू करेगा <code>Eat</code> उपवर्ग से अलग <code>Wolf</code>, लेकिन कोई आह्वान कर सकता है <code>Eat</code> पशु के रूप में संदर्भित किसी भी वर्ग के उदाहरण पर, और प्राप्त करें <code>Eat</code> विशिष्ट उपवर्ग का व्यवहार। | ||
< | <syntaxhighlight lang="cpp"> | ||
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; | |||
} | } | ||
}; | }; | ||
</ | </syntaxhighlight> | ||
यह एक प्रोग्रामर को क्लास के ऑब्जेक्ट्स की सूची को प्रोसेस करने की अनुमति देता है <code>Animal</code>प्रत्येक को बारी-बारी से खाने के लिए कहना (कॉल करके)। <code>Eat</code>), यह जानने की आवश्यकता के बिना कि सूची में किस प्रकार का जानवर हो सकता है, प्रत्येक जानवर कैसे खाता है, या संभावित प्रकार के जानवरों का पूरा सेट क्या हो सकता है। | यह एक प्रोग्रामर को क्लास के ऑब्जेक्ट्स की सूची को प्रोसेस करने की अनुमति देता है <code>Animal</code>प्रत्येक को बारी-बारी से खाने के लिए कहना (कॉल करके)। <code>Eat</code>), यह जानने की आवश्यकता के बिना कि सूची में किस प्रकार का जानवर हो सकता है, प्रत्येक जानवर कैसे खाता है, या संभावित प्रकार के जानवरों का पूरा सेट क्या हो सकता है। | ||
सी में, आभासी कार्यों के पीछे का तंत्र निम्नलिखित तरीके से प्रदान किया जा सकता है: | सी में, आभासी कार्यों के पीछे का तंत्र निम्नलिखित तरीके से प्रदान किया जा सकता है: | ||
< | <syntaxhighlight lang="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 | 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 | |||
} | } | ||
</ | </syntaxhighlight> | ||
[[Category:All articles with unsourced statements|Virtual Function]] | |||
[[Category:Articles with invalid date parameter in template|Virtual Function]] | |||
[[Category:Articles with unsourced statements from October 2021|Virtual Function]] | |||
[[Category:C++ कोड के उदाहरण वाले लेख|Virtual Function]] | |||
[[Category:Created On 16/02/2023|Virtual Function]] | |||
[[Category:Machine Translated Page|Virtual Function]] | |||
[[Category:Pages with script errors|Virtual Function]] | |||
[[Category:Short description with empty Wikidata description|Virtual Function]] | |||
[[Category:Template documentation pages|Short description/doc]] | |||
[[Category:Templates Vigyan Ready|Virtual Function]] | |||
== [[सार वर्ग]] और शुद्ध आभासी कार्य == | == [[सार वर्ग]] और शुद्ध आभासी कार्य == |
Revision as of 11:09, 18 February 2023
ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग में, सी ++ और वस्तु पास्कल जैसी भाषाओं में, वर्चुअल फ़ंक्शन या वर्चुअल विधि एक अंतर्निहित और विधि ओवरराइडिंग (प्रोग्रामिंग) फ़ंक्शन (कंप्यूटर विज्ञान) या विधि (कंप्यूटर विज्ञान) है जिसके लिए गतिशील प्रेषण की सुविधा है। यह अवधारणा ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग (OOP) के (रनटाइम) बहुरूपता (कंप्यूटर विज्ञान) भाग का एक महत्वपूर्ण हिस्सा है। संक्षेप में, एक वर्चुअल फ़ंक्शन निष्पादित किए जाने वाले लक्ष्य फ़ंक्शन को परिभाषित करता है, लेकिन लक्ष्य संकलन समय पर ज्ञात नहीं हो सकता है।
अधिकांश प्रोग्रामिंग लैंग्वेज, जैसे कि जावास्क्रिप्ट, पीएचपी और पायथन (प्रोग्रामिंग लैंग्वेज), डिफ़ॉल्ट रूप से सभी तरीकों को वर्चुअल मानते हैं[1][2] और इस व्यवहार को बदलने के लिए संशोधक प्रदान न करें। हालाँकि, कुछ भाषाएँ संशोधक प्रदान करती हैं ताकि विधियों को व्युत्पन्न कक्षाओं द्वारा ओवरराइड होने से रोका जा सके (जैसे कि जावा में अंतिम कीवर्ड (प्रोग्रामिंग भाषा)[3] और पीएचपी[4]).
उद्देश्य
वर्चुअल फ़ंक्शन की अवधारणा निम्न समस्या हल करती है:
ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग में, जब एक व्युत्पन्न वर्ग बेस क्लास से विरासत में मिलता है, तो व्युत्पन्न वर्ग का एक ऑब्जेक्ट व्युत्पन्न वर्ग प्रकार के बजाय बेस क्लास प्रकार के पॉइंटर (कंप्यूटर प्रोग्रामिंग) या संदर्भ (कंप्यूटर विज्ञान) के माध्यम से संदर्भित किया जा सकता है। . यदि व्युत्पन्न वर्ग द्वारा ओवरराइड किए गए आधार वर्ग के तरीके हैं, तो वास्तव में इस तरह के संदर्भ या सूचक द्वारा बुलाए गए तरीके को सूचक या संदर्भ के घोषित प्रकार के अनुसार, 'प्रारंभिक' (संकलक द्वारा) बाध्य (लिंक) किया जा सकता है, या 'लेट' (अर्थात् भाषा के रनटाइम सिस्टम द्वारा), वस्तु के वास्तविक प्रकार के अनुसार संदर्भित किया जाता है।
आभासी कार्यों को 'देर' से हल किया जाता है। यदि विचाराधीन फ़ंक्शन बेस क्लास में 'वर्चुअल' है, तो फ़ंक्शन के सबसे व्युत्पन्न वर्ग के कार्यान्वयन को पॉइंटर या संदर्भ के घोषित प्रकार की परवाह किए बिना संदर्भित वस्तु के वास्तविक प्रकार के अनुसार कहा जाता है। यदि यह 'आभासी' नहीं है, तो विधि 'प्रारंभिक' हल हो जाती है और सूचक या संदर्भ के घोषित प्रकार के अनुसार चुनी जाती है।
वर्चुअल फ़ंक्शंस प्रोग्राम को उन विधियों को कॉल करने की अनुमति देते हैं जो कोड संकलित होने के समय जरूरी नहीं हैं।[citation needed]
C++ में, आभासी विधियों को जोड़कर घोषित किया जाता है virtual
बेस क्लास में फ़ंक्शन की घोषणा के लिए कीवर्ड। यह संशोधक व्युत्पन्न कक्षाओं में उस पद्धति के सभी कार्यान्वयनों द्वारा विरासत में मिला है, जिसका अर्थ है कि वे एक-दूसरे को ओवर-राइड करना जारी रख सकते हैं और लेट-बाउंड हो सकते हैं। और यहां तक कि अगर बेस क्लास के स्वामित्व वाली विधियां वर्चुअल विधि को कॉल करती हैं, तो वे इसके बजाय व्युत्पन्न विधि को कॉल करेंगे। ओवरलोडिंग तब होती है जब एक वर्ग में दो या दो से अधिक विधियों का एक ही विधि नाम होता है लेकिन अलग-अलग पैरामीटर होते हैं। ओवरराइडिंग का अर्थ है एक ही विधि नाम और मापदंडों के साथ दो विधियाँ होना। ओवरलोडिंग को फंक्शन मैचिंग और ओवरराइडिंग को डायनामिक फंक्शन मैपिंग भी कहा जाता है।
उदाहरण
सी ++
उदाहरण के लिए, एक आधार वर्ग Animal
वर्चुअल फ़ंक्शन हो सकता है Eat
. उपवर्ग Llama
लागू करेगा Eat
उपवर्ग से अलग Wolf
, लेकिन कोई आह्वान कर सकता है Eat
पशु के रूप में संदर्भित किसी भी वर्ग के उदाहरण पर, और प्राप्त करें 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
), यह जानने की आवश्यकता के बिना कि सूची में किस प्रकार का जानवर हो सकता है, प्रत्येक जानवर कैसे खाता है, या संभावित प्रकार के जानवरों का पूरा सेट क्या हो सकता है।
सी में, आभासी कार्यों के पीछे का तंत्र निम्नलिखित तरीके से प्रदान किया जा सकता है:
#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] कुछ डिज़ाइन पैटर्न (कंप्यूटर विज्ञान), जैसे सार फैक्टरी पैटर्न, इस क्षमता का समर्थन करने वाली भाषाओं में सक्रिय रूप से इस उपयोग को बढ़ावा देते हैं।
आभासी विनाशक
ऑब्जेक्ट-ओरिएंटेड लैंग्वेज आमतौर पर मेमोरी एलोकेशन और डी-एलोकेशन को अपने आप मैनेज करती हैं, जब ऑब्जेक्ट बनते और नष्ट होते हैं। हालाँकि, कुछ ऑब्जेक्ट-ओरिएंटेड भाषाएँ वांछित होने पर कस्टम डिस्ट्रक्टर विधि को लागू करने की अनुमति देती हैं। यदि विचाराधीन भाषा स्वचालित मेमोरी प्रबंधन का उपयोग करती है, तो कस्टम डिस्ट्रक्टर (आमतौर पर इस संदर्भ में एक फ़ाइनलाइज़र कहा जाता है) जिसे प्रश्न में वस्तु के लिए उपयुक्त कहा जाता है। उदाहरण के लिए, यदि वुल्फ प्रकार का एक ऑब्जेक्ट जो एनिमल को इनहेरिट करता है, बनाया गया है, और दोनों में कस्टम डिस्ट्रक्टर्स हैं, जिसे वुल्फ में घोषित किया जाएगा।
मैन्युअल स्मृति प्रबंधन संदर्भों में, स्थिति अधिक जटिल हो सकती है, विशेष रूप से स्थैतिक प्रेषण के संबंध में। यदि वुल्फ प्रकार का एक ऑब्जेक्ट बनाया गया है, लेकिन एक एनिमल पॉइंटर द्वारा इंगित किया गया है, और यह एनिमल पॉइंटर प्रकार है जिसे हटा दिया गया है, तो कहा जाने वाला विध्वंसक वास्तव में एनिमल के लिए परिभाषित हो सकता है और वुल्फ के लिए नहीं, जब तक कि विध्वंसक आभासी न हो . यह विशेष रूप से सी ++ के मामले में है, जहां विनाशक आभासी नहीं होने पर व्यवहार प्रोग्रामिंग त्रुटियों का एक आम स्रोत है।
यह भी देखें
- सार विधि
- वंशानुक्रम (कंप्यूटर विज्ञान)
- सुपर क्लास (कंप्यूटर साइंस)
- आभासी विरासत
- वर्चुअल क्लास
- इंटरफ़ेस (ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग)
- घटक वस्तु मॉडल
- आभासी विधि तालिका
संदर्भ
- ↑ "Polymorphism (The Java™ Tutorials > Learning the Java Language > Interfaces and Inheritance)". docs.oracle.com. Retrieved 2020-07-11.
- ↑ "9. Classes — Python 3.9.2 documentation". docs.python.org. Retrieved 2021-02-23.
- ↑ "Writing Final Classes and Methods (The Java™ Tutorials > Learning the Java Language > Interfaces and Inheritance)". docs.oracle.com. Retrieved 2020-07-11.
- ↑ "PHP: Final Keyword - Manual". www.php.net. Retrieved 2020-07-11.
- ↑ Pure virtual destructors - cppreference.com
- ↑ "abc — Abstract Base Classes: @abc.abstractmethod"
- ↑ 7.0 7.1 "N4659: Working Draft, Standard for Programming Language C++" (PDF).
- ↑ 8.0 8.1 Chen, Raymond (April 28, 2004). "What is __purecall?".
- ↑ Meyers, Scott (June 6, 2005). "Never Call Virtual Functions during Construction or Destruction".
- ↑ Chen, Raymond (October 11, 2013). "C++ corner case: You can implement pure virtual functions in the base class".
- ↑ Ganesh, S.G. (August 1, 2011). "Joy of Programming: Calling Virtual Functions from Constructors".