जवाबों:
से विकिपीडिया के आभासी समारोह ...
ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग में, C ++, और ऑब्जेक्ट पास्कल जैसी भाषाओं में, एक वर्चुअल फंक्शन या वर्चुअल मेथड एक इनहेरिटेबल और ओवरराइडेबल फंक्शन या मेथड है, जिसके लिए डायनामिक डिस्पैच की सुविधा है। यह अवधारणा ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग (OOP) के (रनटाइम) बहुरूपता वाले हिस्से का एक महत्वपूर्ण हिस्सा है। संक्षेप में, एक वर्चुअल फ़ंक्शन एक लक्षित फ़ंक्शन को निष्पादित करने के लिए निर्धारित करता है, लेकिन संकलन समय पर लक्ष्य ज्ञात नहीं हो सकता है।
एक गैर-आभासी फ़ंक्शन के विपरीत, जब किसी आभासी फ़ंक्शन को ओवरराइड किया जाता है तो क्लास-पदानुक्रम के सभी स्तरों पर सबसे अधिक व्युत्पन्न संस्करण का उपयोग किया जाता है, बजाय इसके कि यह जिस स्तर पर बनाया गया था। इसलिए यदि बेस क्लास की एक विधि एक आभासी विधि कहती है, तो बेस क्लास में परिभाषित संस्करण के बजाय व्युत्पन्न वर्ग में परिभाषित संस्करण का उपयोग किया जाएगा।
यह गैर-आभासी कार्यों के विपरीत है, जिसे अभी भी एक व्युत्पन्न वर्ग में ओवरराइड किया जा सकता है, लेकिन "नया" संस्करण केवल व्युत्पन्न वर्ग और नीचे से उपयोग किया जाएगा, लेकिन बेस क्लास की कार्यक्षमता को बिल्कुल भी नहीं बदलेगा।
जहाँ तक..
एक शुद्ध आभासी फ़ंक्शन या शुद्ध आभासी विधि एक आभासी फ़ंक्शन है जिसे व्युत्पन्न वर्ग द्वारा कार्यान्वित किया जाना आवश्यक है यदि व्युत्पन्न वर्ग सार नहीं है।
जब एक शुद्ध आभासी विधि मौजूद होती है, तो कक्षा "अमूर्त" होती है और इसे अपने दम पर त्वरित नहीं किया जा सकता है। इसके बजाय, एक व्युत्पन्न वर्ग जो शुद्ध-आभासी विधि (ओं) को लागू करता है, का उपयोग किया जाना चाहिए। एक शुद्ध-आभासी को बेस-क्लास में बिल्कुल भी परिभाषित नहीं किया जाता है, इसलिए एक व्युत्पन्न वर्ग को इसे परिभाषित करना चाहिए , या वह व्युत्पन्न वर्ग भी सार है, और इसे तत्काल नहीं किया जा सकता है। केवल एक ऐसा वर्ग जिसमें कोई अमूर्त विधियाँ नहीं हैं, तत्काल किया जा सकता है।
एक वर्चुअल बेस क्लास की कार्यक्षमता को ओवरराइड करने का एक तरीका प्रदान करता है, और एक शुद्ध-वर्चुअल को इसकी आवश्यकता होती है।
pure
कीवर्ड जोड़ना चाहता था , लेकिन वह बेल लैब्स C ++ की एक बड़ी रिलीज़ करने वाला था, और उसका मैनेजर उस लेट स्टेज पर इसकी अनुमति नहीं देगा। कीवर्ड जोड़ना एक बड़ी बात है।
मैं विकिपीडिया की आभासी की परिभाषा पर टिप्पणी करना चाहूंगा, जैसा कि कई लोगों ने यहां दोहराया है। [जिस समय यह उत्तर लिखा गया था,] विकिपीडिया ने एक आभासी पद्धति को परिभाषित किया, जिसे उपवर्गों में ओवरराइड किया जा सकता है। [सौभाग्य से, विकिपीडिया को तब से संपादित किया गया है, और यह अब इसे सही ढंग से समझाता है।] यह गलत है: किसी भी विधि, न केवल आभासी वाले, उपवर्गों में ओवरराइड किया जा सकता है। आपको पॉलीमॉर्फिज़्म देने के लिए वर्चुअल क्या करना है, यानी रन-टाइम को चुनने की क्षमता एक विधि का सबसे व्युत्पन्न ओवरराइड है ।
निम्नलिखित कोड पर विचार करें:
#include <iostream>
using namespace std;
class Base {
public:
void NonVirtual() {
cout << "Base NonVirtual called.\n";
}
virtual void Virtual() {
cout << "Base Virtual called.\n";
}
};
class Derived : public Base {
public:
void NonVirtual() {
cout << "Derived NonVirtual called.\n";
}
void Virtual() {
cout << "Derived Virtual called.\n";
}
};
int main() {
Base* bBase = new Base();
Base* bDerived = new Derived();
bBase->NonVirtual();
bBase->Virtual();
bDerived->NonVirtual();
bDerived->Virtual();
}
इस कार्यक्रम का आउटपुट क्या है?
Base NonVirtual called.
Base Virtual called.
Base NonVirtual called.
Derived Virtual called.
व्युत्पन्न बेस की हर विधि को ओवरराइड करता है: न केवल आभासी एक है, बल्कि गैर-आभासी भी है।
हम देखते हैं कि जब आपके पास बेस-पॉइंटर-टू-डेरिव्ड (bDerived) होता है, तो NonVirtual को बेस क्लास कार्यान्वयन कहते हैं। यह संकलन-समय पर हल किया गया है: संकलक देखता है कि bDerived एक Base * है, जो NonVirtual वर्चुअल नहीं है, इसलिए यह क्लास बेस पर रिज़ॉल्यूशन करता है।
हालाँकि, वर्चुअल कॉलिंग व्युत्पन्न वर्ग कार्यान्वयन को बुलाता है। कीवर्ड वर्चुअल होने के कारण, विधि का चयन रन-टाइम पर होता है , संकलन-समय पर नहीं। कंपाइल-टाइम पर यहां क्या होता है, कंपाइलर देखता है कि यह एक बेस * है, और यह कि यह एक वर्चुअल तरीका कह रहा है, इसलिए यह क्लास बेस के बजाय वाइबल पर कॉल डालता है। रन-टाइम पर इस वॉयटेबल का त्वरित मूल्यांकन किया जाता है, इसलिए रन-टाइम रिज़ॉल्यूशन सबसे अधिक व्युत्पन्न ओवरराइड के लिए।
मुझे आशा है कि यह बहुत भ्रामक नहीं था। संक्षेप में, किसी भी विधि को ओवरराइड किया जा सकता है, लेकिन केवल आभासी तरीके आपको बहुरूपता प्रदान करते हैं, अर्थात, सबसे अधिक व्युत्पन्न ओवरराइड का रन-टाइम चयन। व्यवहार में, हालांकि, एक गैर-आभासी पद्धति को ओवरराइड करना बुरा व्यवहार माना जाता है और शायद ही कभी इसका इस्तेमाल किया जाता है, इसलिए बहुत से लोग (जिनमें कोई भी लिखा हो कि विकिपीडिया लेख) लगता है कि केवल आभासी तरीकों को ओवरराइड किया जा सकता है।
Derived*
पॉइंट होम ड्राइव करने के लिए समान फ़ंक्शन कॉल के साथ जोड़ना मददगार हो सकता है । अन्यथा महान जवाब
वर्चुअल कीवर्ड पॉलीमॉर्फिज्म को सपोर्ट करने के लिए C ++ को अपनी क्षमता देता है। जब आपके पास कुछ वर्ग के ऑब्जेक्ट के लिए एक पॉइंटर होता है जैसे:
class Animal
{
public:
virtual int GetNumberOfLegs() = 0;
};
class Duck : public Animal
{
public:
int GetNumberOfLegs() { return 2; }
};
class Horse : public Animal
{
public:
int GetNumberOfLegs() { return 4; }
};
void SomeFunction(Animal * pAnimal)
{
cout << pAnimal->GetNumberOfLegs();
}
इस (मूर्खतापूर्ण) उदाहरण में, GetNumberOfLegs () फ़ंक्शन ऑब्जेक्ट के वर्ग के आधार पर उचित संख्या देता है जिसे इसके लिए कहा जाता है।
अब, 'SomeFunction' फ़ंक्शन पर विचार करें। यह परवाह नहीं करता है कि पशु किस प्रकार की वस्तु को पारित किया गया है, जब तक कि वह पशु से प्राप्त होता है। कंपाइलर किसी भी पशु-व्युत्पन्न वर्ग को पशु के रूप में स्वचालित रूप से डालेगा क्योंकि यह एक आधार वर्ग है।
यदि हम ऐसा करते हैं:
Duck d;
SomeFunction(&d);
यह '2' का उत्पादन करेगा। यदि हम ऐसा करते हैं:
Horse h;
SomeFunction(&h);
यह '4' का उत्पादन करेगा। हम ऐसा नहीं कर सकते:
Animal a;
SomeFunction(&a);
क्योंकि यह GetNumberOfLegs () वर्चुअल फ़ंक्शन के शुद्ध होने के कारण संकलित नहीं होगा, जिसका अर्थ है कि इसे व्युत्पन्न वर्गों (उपवर्गों) द्वारा लागू किया जाना चाहिए।
शुद्ध वर्चुअल फ़ंक्शंस को अधिकतर परिभाषित करने के लिए उपयोग किया जाता है:
a) अमूर्त वर्ग
ये आधार वर्ग हैं जहां आपको उनसे प्राप्त करना है और फिर शुद्ध आभासी कार्यों को लागू करना है।
बी) इंटरफेस
ये 'खाली' वर्ग हैं जहां सभी कार्य शुद्ध आभासी हैं और इसलिए आपको सभी कार्यों को प्राप्त करना होगा और फिर उन्हें लागू करना होगा।
C ++ क्लास में, वर्चुअल वह कीवर्ड होता है, जो इसे डिजाइन करता है, एक विधि को ओवरक्लेड (यानी द्वारा कार्यान्वित किया जाता है) उपक्लास किया जा सकता है। उदाहरण के लिए:
class Shape
{
public:
Shape();
virtual ~Shape();
std::string getName() // not overridable
{
return m_name;
}
void setName( const std::string& name ) // not overridable
{
m_name = name;
}
protected:
virtual void initShape() // overridable
{
setName("Generic Shape");
}
private:
std::string m_name;
};
इस मामले में एक उपवर्ग कुछ विशेष कार्य करने के लिए initShape फ़ंक्शन को ओवरराइड कर सकता है :
class Square : public Shape
{
public:
Square();
virtual ~Square();
protected:
virtual void initShape() // override the Shape::initShape function
{
setName("Square");
}
}
अवधि शुद्ध आभासी आभासी कार्यों एक उपवर्ग द्वारा कार्यान्वित किया जा करने की जरूरत है और आधार वर्ग द्वारा कार्यान्वित नहीं किया गया है कि को दर्शाता है। आप वर्चुअल कीवर्ड का उपयोग करके और विधि घोषणा के अंत में एक = 0 जोड़कर एक विधि को शुद्ध आभासी के रूप में नामित करते हैं ।
इसलिए, यदि आप आकृति बनाना चाहते हैं :: initShape शुद्ध आभासी तो आप निम्न कार्य करेंगे:
class Shape
{
...
virtual void initShape() = 0; // pure virtual method
...
};
अपनी कक्षा में एक शुद्ध आभासी विधि जोड़कर आप कक्षा को एक बनाते हैं सार आधार वर्ग जो कार्यान्वयन से इंटरफेस को अलग करने के लिए बहुत आसान है।
m_name
। क्या m_
मतलब है?
"वर्चुअल" का मतलब है कि विधि उपवर्गों में ओवरराइड हो सकती है, लेकिन बेस क्लास में सीधे-कॉल करने योग्य कार्यान्वयन है। "शुद्ध आभासी" का मतलब है कि यह एक आभासी तरीका है जिसमें कोई सीधे-कॉल करने योग्य कार्यान्वयन नहीं है। इस तरह की विधि होनी चाहिए वंशानुगत पदानुक्रम में कम से कम एक बार ओवरराइड किया चाहिए - यदि किसी वर्ग के पास कोई भी अनपेक्षित वर्चुअल तरीके हैं, तो उस वर्ग की वस्तुओं का निर्माण नहीं किया जा सकता है और संकलन विफल हो जाएगा।
@quark बताते हैं कि शुद्ध-आभासी तरीकों का कार्यान्वयन हो सकता है, लेकिन जैसा कि शुद्ध-आभासी तरीकों को ओवरराइड किया जाना चाहिए, डिफ़ॉल्ट कार्यान्वयन को सीधे नहीं कहा जा सकता है। यहां डिफ़ॉल्ट के साथ शुद्ध-आभासी विधि का एक उदाहरण दिया गया है:
#include <cstdio>
class A {
public:
virtual void Hello() = 0;
};
void A::Hello() {
printf("A::Hello\n");
}
class B : public A {
public:
void Hello() {
printf("B::Hello\n");
A::Hello();
}
};
int main() {
/* Prints:
B::Hello
A::Hello
*/
B b;
b.Hello();
return 0;
}
टिप्पणियों के अनुसार, संकलन विफल होगा या नहीं यह संकलक-विशिष्ट है। GCC में 4.3.3 कम से कम, यह संकलित नहीं करेगा:
class A {
public:
virtual void Hello() = 0;
};
int main()
{
A a;
return 0;
}
आउटपुट:
$ g++ -c virt.cpp
virt.cpp: In function ‘int main()’:
virt.cpp:8: error: cannot declare variable ‘a’ to be of abstract type ‘A’
virt.cpp:1: note: because the following virtual functions are pure within ‘A’:
virt.cpp:3: note: virtual void A::Hello()
वर्चुअल कीवर्ड कैसे काम करता है?
मान लें कि मनुष्य एक आधार वर्ग है, भारतीय मनुष्य से लिया गया है।
Class Man
{
public:
virtual void do_work()
{}
}
Class Indian : public Man
{
public:
void do_work()
{}
}
Do_work () को वर्चुअल के रूप में घोषित करने का अर्थ है: कॉल करने के लिए do_work () केवल रन-टाइम पर निर्धारित किया जाएगा।
मान लो, मैं
Man *man;
man = new Indian();
man->do_work(); // Indian's do work is only called.
यदि वर्चुअल का उपयोग नहीं किया जाता है, तो संकलक द्वारा निर्धारित ऑब्जेक्ट के आधार पर वैधानिक रूप से निर्धारित या सांख्यिकीय रूप से बाध्य होता है। इसलिए यदि मनुष्य की कोई वस्तु do_work () को कॉल करती है, तो आदमी का do_work () को एक भारतीय उद्देश्य के लिए EVEN THOUGH IT POINTS कहा जाता है
मेरा मानना है कि शीर्ष मतदान का उत्तर भ्रामक है - किसी भी तरीके से आभासी हो या नहीं, इसका व्युत्पन्न वर्ग में एक ओवरराइड कार्यान्वयन हो सकता है। C ++ के विशिष्ट संदर्भ के साथ, सही अंतर रन-टाइम (जब वर्चुअल का उपयोग किया जाता है) बाइंडिंग और कंपाइल-टाइम (जब वर्चुअल का उपयोग नहीं किया जाता है, लेकिन एक विधि ओवरराइड होती है और संबंधित कार्यों के बाइंडिंग में एक ऑब्जेक्ट को इंगित किया जाता है)।
ऐसा लगता है कि एक और भ्रामक टिप्पणी है,
"जस्टिन, 'शुद्ध आभासी' केवल एक शब्द है (एक कीवर्ड नहीं है, नीचे मेरा उत्तर देखें) का अर्थ है" यह फ़ंक्शन आधार वर्ग द्वारा लागू नहीं किया जा सकता है। "
ये गलत है! विशुद्ध रूप से आभासी कार्यों में एक शरीर भी हो सकता है और प्रभावित हो सकता है! सच्चाई यह है कि एक अमूर्त वर्ग का शुद्ध आभासी कार्य सांख्यिकीय रूप से कहा जा सकता है! दो बहुत अच्छे लेखक हैं बज़्ने स्ट्रॉस्ट्रुप और स्टेन लिपमैन .... क्योंकि उन्होंने भाषा लिखी थी।
वर्चुअल फंक्शन एक मेम्बर फंक्शन होता है जिसे बेस क्लास में घोषित किया जाता है और जिसे डिराइव्ड क्लास द्वारा रीडिफाइ किया जाता है। वंशानुक्रम के क्रम में आभासी कार्य क्रमबद्ध होते हैं। जब एक व्युत्पन्न वर्ग एक आभासी फ़ंक्शन को ओवरराइड नहीं करता है, तो उसके बेस क्लास के भीतर परिभाषित फ़ंक्शन का उपयोग किया जाता है।
एक शुद्ध आभासी फ़ंक्शन वह है जिसमें आधार वर्ग के सापेक्ष कोई परिभाषा नहीं होती है। इसका आधार वर्ग में कोई कार्यान्वयन नहीं है। किसी भी व्युत्पन्न वर्ग को इस फ़ंक्शन को ओवरराइड करना चाहिए।
सिमूला, सी ++ और सी #, जो डिफ़ॉल्ट रूप से स्थैतिक विधि बंधन का उपयोग करते हैं, प्रोग्रामर यह निर्दिष्ट कर सकता है कि विशेष तरीकों को आभासी के रूप में लेबल करके गतिशील बंधन का उपयोग करना चाहिए। डायनेमिक विधि बाइंडिंग ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग के लिए केंद्रीय है।
ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग के लिए तीन मूलभूत अवधारणाओं की आवश्यकता होती है: इनकैप्सुलेशन, इनहेरिटेंस, और डायनेमिक विधि बाइंडिंग।
एनकैप्सुलेशन एक अमूर्त के कार्यान्वयन के विवरण को एक सरल इंटरफ़ेस के पीछे छिपाने की अनुमति देता है।
वंशानुक्रम एक नई अमूर्तता को कुछ मौजूदा अमूर्तता के विस्तार या परिशोधन के रूप में परिभाषित करने की अनुमति देता है, कुछ या सभी विशेषताओं को स्वचालित रूप से प्राप्त करता है।
डायनेमिक मेथड बाइंडिंग नए एब्स्ट्रैक्शन को अपने नए व्यवहार को प्रदर्शित करने की अनुमति देता है, जबकि एक संदर्भ में उपयोग किया जाता है जो पुराने एब्सट्रैक्शन की अपेक्षा करता है।
आभासी तरीकों को व्युत्पन्न वर्गों द्वारा ओवरराइड किया जा सकता है, लेकिन बेस क्लास में एक कार्यान्वयन की आवश्यकता होती है (जिसे ओवरराइड किया जाएगा)
शुद्ध आभासी विधियों का आधार वर्ग कोई कार्यान्वयन नहीं है। उन्हें व्युत्पन्न वर्गों द्वारा परिभाषित करने की आवश्यकता है। (इसलिए तकनीकी रूप से ओवरराइड करना सही शब्द नहीं है, क्योंकि ओवरराइड करने के लिए कुछ भी नहीं है)।
वर्चुअल डिफ़ॉल्ट जावा व्यवहार से मेल खाती है, जब व्युत्पन्न वर्ग बेस क्लास की एक विधि को ओवरराइड करता है।
शुद्ध आभासी तरीके अमूर्त वर्गों के भीतर अमूर्त तरीकों के व्यवहार के अनुरूप हैं। और एक वर्ग जिसमें केवल शुद्ध आभासी विधियाँ हैं और स्थिरांक एक अंतरफलक के cpp- लटकन होगा।
शुद्ध आभासी कार्य
इस कोड को आज़माएं
#include <iostream>
using namespace std;
class aClassWithPureVirtualFunction
{
public:
virtual void sayHellow()=0;
};
class anotherClass:aClassWithPureVirtualFunction
{
public:
void sayHellow()
{
cout<<"hellow World";
}
};
int main()
{
//aClassWithPureVirtualFunction virtualObject;
/*
This not possible to create object of a class that contain pure virtual function
*/
anotherClass object;
object.sayHellow();
}
कक्षा में anotherClass समारोह sayHellow हटाने और कोड चलाते हैं। आपको त्रुटि मिलेगी! क्योंकि जब किसी वर्ग में एक शुद्ध आभासी फ़ंक्शन होता है, तो उस वर्ग से कोई भी वस्तु नहीं बनाई जा सकती है और उसे विरासत में मिला है, तो उसके व्युत्पन्न वर्ग को उस फ़ंक्शन को लागू करना होगा।
वर्चुअल फ़ंक्शन
एक और कोड की कोशिश करो
#include <iostream>
using namespace std;
class aClassWithPureVirtualFunction
{
public:
virtual void sayHellow()
{
cout<<"from base\n";
}
};
class anotherClass:public aClassWithPureVirtualFunction
{
public:
void sayHellow()
{
cout<<"from derived \n";
}
};
int main()
{
aClassWithPureVirtualFunction *baseObject=new aClassWithPureVirtualFunction;
baseObject->sayHellow();///call base one
baseObject=new anotherClass;
baseObject->sayHellow();////call the derived one!
}
यहाँ SayHellow फ़ंक्शन को आधार वर्ग में आभासी के रूप में चिह्नित किया गया है। यह संकलक कहता है कि व्युत्पन्न वर्ग में फ़ंक्शन की खोज करने और फ़ंक्शन को लागू करने का प्रयास करें। यदि नहीं मिला है, तो आधार को निष्पादित करें। धन्यवाद
"एक वर्चुअल फंक्शन या वर्चुअल मेथड एक फंक्शन या मेथड है, जिसका व्यवहार एक ही सिग्नेचर वाले फंक्शन द्वारा इनहेरिटिंग क्लास के भीतर ओवरराइड किया जा सकता है" - विकिपीडिया
यह आभासी कार्यों के लिए एक अच्छी व्याख्या नहीं है। क्योंकि, भले ही कोई सदस्य आभासी न हो, विरासत में मिली कक्षाएं इसे ओवरराइड कर सकती हैं। आप इसे स्वयं देख कर देख सकते हैं।
जब फंक्शन एक बेस क्लास को एक पैरामीटर के रूप में लेता है तो अंतर खुद दिखाता है। जब आप इनहेरिटिंग क्लास को इनपुट के रूप में देते हैं, तो वह फ़ंक्शन ओवरराइड फ़ंक्शन के बेस क्लास कार्यान्वयन का उपयोग करता है। हालाँकि, यदि वह फ़ंक्शन वर्चुअल है, तो वह उसी का उपयोग करता है जिसे व्युत्पन्न वर्ग में लागू किया गया है।
वर्चुअल फ़ंक्शंस की बेस क्लास में परिभाषा होनी चाहिए और व्युत्पन्न वर्ग में भी लेकिन आवश्यक नहीं है, उदाहरण के लिए ToString () या toString () फ़ंक्शन एक वर्चुअल है इसलिए आप इसे उपयोगकर्ता-निर्धारित क्लास (एस) में ओवरराइड करके अपना स्वयं का कार्यान्वयन प्रदान कर सकते हैं।
आभासी कार्यों को सामान्य वर्ग में घोषित और परिभाषित किया जाता है।
शुद्ध आभासी फ़ंक्शन को "= 0" के साथ समाप्त घोषित किया जाना चाहिए और इसे केवल सार वर्ग में घोषित किया जा सकता है।
एक शुद्ध वर्चुअल फ़ंक्शन वाले एक अमूर्त वर्ग में उस शुद्ध वर्चुअल फ़ंक्शंस की कोई परिभाषा नहीं हो सकती है, इसलिए इसका तात्पर्य यह है कि कार्यान्वयन उस वर्ग (वर्ग) में प्रदान किया जाना चाहिए जो उस सार वर्ग से प्राप्त होता है।