आभासी / शुद्ध आभासी समझाया


346

यदि किसी फ़ंक्शन को आभासी के रूप में परिभाषित किया जाता है और क्या वह शुद्ध आभासी के समान है तो इसका क्या मतलब है?

जवाबों:


339

से विकिपीडिया के आभासी समारोह ...

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

एक गैर-आभासी फ़ंक्शन के विपरीत, जब किसी आभासी फ़ंक्शन को ओवरराइड किया जाता है तो क्लास-पदानुक्रम के सभी स्तरों पर सबसे अधिक व्युत्पन्न संस्करण का उपयोग किया जाता है, बजाय इसके कि यह जिस स्तर पर बनाया गया था। इसलिए यदि बेस क्लास की एक विधि एक आभासी विधि कहती है, तो बेस क्लास में परिभाषित संस्करण के बजाय व्युत्पन्न वर्ग में परिभाषित संस्करण का उपयोग किया जाएगा।

यह गैर-आभासी कार्यों के विपरीत है, जिसे अभी भी एक व्युत्पन्न वर्ग में ओवरराइड किया जा सकता है, लेकिन "नया" संस्करण केवल व्युत्पन्न वर्ग और नीचे से उपयोग किया जाएगा, लेकिन बेस क्लास की कार्यक्षमता को बिल्कुल भी नहीं बदलेगा।

जहाँ तक..

एक शुद्ध आभासी फ़ंक्शन या शुद्ध आभासी विधि एक आभासी फ़ंक्शन है जिसे व्युत्पन्न वर्ग द्वारा कार्यान्वित किया जाना आवश्यक है यदि व्युत्पन्न वर्ग सार नहीं है।

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

एक वर्चुअल बेस क्लास की कार्यक्षमता को ओवरराइड करने का एक तरीका प्रदान करता है, और एक शुद्ध-वर्चुअल को इसकी आवश्यकता होती है।


10
तो ... शुद्ध आभासी एक खोजशब्द है, या सिर्फ एक शब्द जो प्रयोग किया जाता है?
जस्टिन

197
आभासी शून्य फ़ंक्शन () = 0; एक शुद्ध आभासी है। "= 0" इंगित करता है कि शुद्धता है।
Goz

8
जस्टिन, 'शुद्ध आभासी' सिर्फ एक शब्द है (एक कीवर्ड नहीं, नीचे मेरा उत्तर देखें) का अर्थ "इस फ़ंक्शन को आधार वर्ग द्वारा लागू नहीं किया जा सकता है। जैसा कि गूज ने कहा," = 0 "को एक आभासी के अंत तक जोड़ते हुए। समारोह इसे "शुद्ध" बनाता है
निक हद्दाद

14
मेरा मानना ​​है कि स्ट्रॉस्ट्रुप ने कहा कि वह एक pureकीवर्ड जोड़ना चाहता था , लेकिन वह बेल लैब्स C ++ की एक बड़ी रिलीज़ करने वाला था, और उसका मैनेजर उस लेट स्टेज पर इसकी अनुमति नहीं देगा। कीवर्ड जोड़ना एक बड़ी बात है।
क्वार्क

14
यह एक अच्छा जवाब नहीं है। किसी भी विधि को केवल आभासी लोगों को ही नहीं देखा जा सकता है। अधिक जानकारी के लिए मेरा जवाब देखें।
Asik

212

मैं विकिपीडिया की आभासी की परिभाषा पर टिप्पणी करना चाहूंगा, जैसा कि कई लोगों ने यहां दोहराया है। [जिस समय यह उत्तर लिखा गया था,] विकिपीडिया ने एक आभासी पद्धति को परिभाषित किया, जिसे उपवर्गों में ओवरराइड किया जा सकता है। [सौभाग्य से, विकिपीडिया को तब से संपादित किया गया है, और यह अब इसे सही ढंग से समझाता है।] यह गलत है: किसी भी विधि, न केवल आभासी वाले, उपवर्गों में ओवरराइड किया जा सकता है। आपको पॉलीमॉर्फिज़्म देने के लिए वर्चुअल क्या करना है, यानी रन-टाइम को चुनने की क्षमता एक विधि का सबसे व्युत्पन्न ओवरराइड है

निम्नलिखित कोड पर विचार करें:

#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 वर्चुअल नहीं है, इसलिए यह क्लास बेस पर रिज़ॉल्यूशन करता है।

हालाँकि, वर्चुअल कॉलिंग व्युत्पन्न वर्ग कार्यान्वयन को बुलाता है। कीवर्ड वर्चुअल होने के कारण, विधि का चयन रन-टाइम पर होता है , संकलन-समय पर नहीं। कंपाइल-टाइम पर यहां क्या होता है, कंपाइलर देखता है कि यह एक बेस * है, और यह कि यह एक वर्चुअल तरीका कह रहा है, इसलिए यह क्लास बेस के बजाय वाइबल पर कॉल डालता है। रन-टाइम पर इस वॉयटेबल का त्वरित मूल्यांकन किया जाता है, इसलिए रन-टाइम रिज़ॉल्यूशन सबसे अधिक व्युत्पन्न ओवरराइड के लिए।

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


6
सिर्फ इसलिए कि विकिपीडिया लेख (जिसका मैं कोई बचाव नहीं कर रहा हूं) एक आभासी पद्धति को परिभाषित करता है "एक के रूप में जिसे उपवर्गों में ओवरराइड किया जा सकता है" इस संभावना को बाहर नहीं करता है कि अन्य, गैर-आभासी, समान नाम वाले तरीकों को घोषित किया जा सकता है। इसे ओवरलोडिंग के रूप में जाना जाता है।

26
परिभाषा फिर भी गलत है। एक विधि जिसे एक व्युत्पन्न वर्ग में ओवरराइड किया जा सकता है वह परिभाषा से आभासी नहीं है; क्या विधि को ओवरराइड किया जा सकता है "आभासी" की परिभाषा के लिए अप्रासंगिक है। इसके अलावा, "ओवरलोडिंग" आम तौर पर एक ही नाम के साथ एक ही नाम और वापसी प्रकार लेकिन विभिन्न तर्कों के साथ कई तरीकों को संदर्भित करता है; यह "ओवरराइडिंग" से बहुत अलग है जो बिल्कुल एक ही हस्ताक्षर लेकिन एक व्युत्पन्न वर्ग में है। जब इसे गैर-बहुरूपिक (गैर-आभासी आधार) किया जाता है, तो इसे अक्सर "छिपाना" कहा जाता है।
आशिक

5
यह स्वीकृत उत्तर होना चाहिए। वह विशेष विकिपीडिया लेख जिसे मैं यहाँ लिंक करने के लिए समय लूंगा क्योंकि इस प्रश्न पर किसी और ने नहीं किया है , पूरा कचरा है। +1, अच्छा सर।
जोसफातव

2
अब समझ में आता है। धन्यवाद, अच्छा सर, ठीक से समझाने के लिए कि किसी भी पद्धति को व्युत्पन्न वर्गों से अलग किया जा सकता है और परिवर्तन यह है कि संकलक कैसे व्यवहार करेगा कि विभिन्न स्थितियों में क्या फ़ंक्शन का चयन किया जाए।
दूनद

3
Derived*पॉइंट होम ड्राइव करने के लिए समान फ़ंक्शन कॉल के साथ जोड़ना मददगार हो सकता है । अन्यथा महान जवाब
जेफ जोन्स

114

वर्चुअल कीवर्ड पॉलीमॉर्फिज्म को सपोर्ट करने के लिए 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) अमूर्त वर्ग

ये आधार वर्ग हैं जहां आपको उनसे प्राप्त करना है और फिर शुद्ध आभासी कार्यों को लागू करना है।

बी) इंटरफेस

ये 'खाली' वर्ग हैं जहां सभी कार्य शुद्ध आभासी हैं और इसलिए आपको सभी कार्यों को प्राप्त करना होगा और फिर उन्हें लागू करना होगा।


अपने उदाहरण में, आप # 4 नहीं कर सकते क्योंकि आपने शुद्ध आभासी पद्धति का कार्यान्वयन प्रदान नहीं किया था। यह कड़ाई से नहीं है क्योंकि विधि शुद्ध आभासी है।
इहानी

@ जिहनी आप आधार वर्ग में शुद्ध आभासी पद्धति को लागू नहीं कर सकते। इसलिए केस # 4 अभी भी त्रुटि है।
प्रसाद

32

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
 ... 
};

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


1
"आभासी कार्यों के बारे में जिन्हें एक उपवर्ग द्वारा लागू किया जाना चाहिए" - यह कड़ाई से सच नहीं है, लेकिन अगर वे नहीं हैं तो उपवर्ग भी सार है। और अमूर्त वर्गों को तत्काल नहीं किया जा सकता है। इसके अलावा, "बेस क्लास द्वारा लागू नहीं किया जा सकता" भ्रामक लगता है; मेरा सुझाव है कि "नहीं किया गया" बेहतर होगा क्योंकि आधार वर्ग के भीतर कार्यान्वयन को जोड़ने के लिए कोड के संशोधनों पर कोई प्रतिबंध नहीं है।
NVRAM

2
और "getName फ़ंक्शन को उपवर्ग द्वारा लागू नहीं किया जा सकता है" बिल्कुल सही नहीं है। उपवर्ग विधि (w / समान या अलग हस्ताक्षर) को लागू कर सकते हैं, लेकिन यह कार्यान्वयन विधि को पूरा नहीं करेगा। आप एक उपवर्ग के रूप में सर्किल को लागू कर सकते हैं और "std :: string Circle :: getName ()" को लागू कर सकते हैं - फिर आप किसी वृत्त उदाहरण के लिए विधि कह सकते हैं। लेकिन अगर शेप पॉइंटर या रेफरेंस के जरिए इस्तेमाल किया जाता है तो कंपाइलर शेप :: getName () कहलाएगा।
एनवीआरएएम

1
दोनों मोर्चों पर अच्छे अंक। मैं इस उदाहरण के लिए विशेष मामलों पर चर्चा करने से दूर रहने की कोशिश कर रहा था, मैं अधिक क्षमाशील होने के उत्तर को संशोधित करूंगा। धन्यवाद!
निक हदद

@NickHaddad पुराना धागा, लेकिन सोच रहा था कि आपने अपने चर को क्यों बुलाया m_name। क्या m_मतलब है?
त्कन

1
@Tqn ने निकाहदाद का मानना ​​है कि परंपराओं का पालन किया है, m_name एक नामकरण सम्मेलन है जिसे आमतौर पर हंगेरियन नोटेशन कहा जाता है। एम एक संरचना / वर्ग, पूर्णांक के सदस्य को इंगित करता है।
केटकम्प

16

"वर्चुअल" का मतलब है कि विधि उपवर्गों में ओवरराइड हो सकती है, लेकिन बेस क्लास में सीधे-कॉल करने योग्य कार्यान्वयन है। "शुद्ध आभासी" का मतलब है कि यह एक आभासी तरीका है जिसमें कोई सीधे-कॉल करने योग्य कार्यान्वयन नहीं है। इस तरह की विधि होनी चाहिए वंशानुगत पदानुक्रम में कम से कम एक बार ओवरराइड किया चाहिए - यदि किसी वर्ग के पास कोई भी अनपेक्षित वर्चुअल तरीके हैं, तो उस वर्ग की वस्तुओं का निर्माण नहीं किया जा सकता है और संकलन विफल हो जाएगा।

@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()

यदि आप कक्षा के एक उदाहरण को तत्काल करना चाहते हैं तो इसे ओवरराइड किया जाना चाहिए। यदि आप कोई उदाहरण नहीं बनाते हैं तो कोड ठीक संकलित करेगा।
Glen

1
संकलन विफल नहीं होगा। यदि कोई (शुद्ध) आभासी विधि का कार्यान्वयन नहीं होता है, तो उस वर्ग / वस्तु को तत्काल नहीं किया जा सकता है। यह लिंक नहीं कर सकता है, लेकिन यह संकलन करेगा।
टिम

@Glen, @tim: किस कंपाइलर पर? जब मैं एक प्रोग्राम को संकलित करने की कोशिश करता हूं जो एक अमूर्त वर्ग बनाता है, तो यह संकलन नहीं करता है।
जॉन मिलिकिन

@ जॉन संकलन केवल तभी विफल हो जाएगा जब आप किसी ऐसे वर्ग का उदाहरण प्रस्तुत करने का प्रयास करेंगे जिसमें पीवीएफ शामिल हो। आप निश्चित रूप से ऐसी कक्षाओं के लिए पॉइंटर या रेफरेंस मानों को तुरंत कर सकते हैं।

5
इसके अलावा, जॉन, निम्नलिखित बिल्कुल सही नहीं है: "शुद्ध आभासी 'का अर्थ है कि यह एक आभासी तरीका है जिसमें कोई कार्यान्वयन नहीं है।" शुद्ध आभासी तरीकों में कार्यान्वयन हो सकता है। लेकिन आप उन्हें सीधे नहीं बुला सकते हैं: आपको उप-वर्ग के भीतर से बेस क्लास कार्यान्वयन को ओवरराइड और उपयोग करना होगा। यह आपको कार्यान्वयन का एक डिफ़ॉल्ट हिस्सा प्रदान करने की अनुमति देता है। हालांकि यह एक सामान्य तकनीक नहीं है।
क्वार्क

9

वर्चुअल कीवर्ड कैसे काम करता है?

मान लें कि मनुष्य एक आधार वर्ग है, भारतीय मनुष्य से लिया गया है।

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 ++ के विशिष्ट संदर्भ के साथ, सही अंतर रन-टाइम (जब वर्चुअल का उपयोग किया जाता है) बाइंडिंग और कंपाइल-टाइम (जब वर्चुअल का उपयोग नहीं किया जाता है, लेकिन एक विधि ओवरराइड होती है और संबंधित कार्यों के बाइंडिंग में एक ऑब्जेक्ट को इंगित किया जाता है)।

ऐसा लगता है कि एक और भ्रामक टिप्पणी है,

"जस्टिन, 'शुद्ध आभासी' केवल एक शब्द है (एक कीवर्ड नहीं है, नीचे मेरा उत्तर देखें) का अर्थ है" यह फ़ंक्शन आधार वर्ग द्वारा लागू नहीं किया जा सकता है। "

ये गलत है! विशुद्ध रूप से आभासी कार्यों में एक शरीर भी हो सकता है और प्रभावित हो सकता है! सच्चाई यह है कि एक अमूर्त वर्ग का शुद्ध आभासी कार्य सांख्यिकीय रूप से कहा जा सकता है! दो बहुत अच्छे लेखक हैं बज़्ने स्ट्रॉस्ट्रुप और स्टेन लिपमैन .... क्योंकि उन्होंने भाषा लिखी थी।


2
दुर्भाग्य से एक बार उत्तर मिलने के बाद, बाकी सभी को नजरअंदाज कर दिया जाएगा। यहां तक ​​कि वे बेहतर हो सकते हैं।
लेटॉर्फ

3

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

एक शुद्ध आभासी फ़ंक्शन वह है जिसमें आधार वर्ग के सापेक्ष कोई परिभाषा नहीं होती है। इसका आधार वर्ग में कोई कार्यान्वयन नहीं है। किसी भी व्युत्पन्न वर्ग को इस फ़ंक्शन को ओवरराइड करना चाहिए।


2

सिमूला, सी ++ और सी #, जो डिफ़ॉल्ट रूप से स्थैतिक विधि बंधन का उपयोग करते हैं, प्रोग्रामर यह निर्दिष्ट कर सकता है कि विशेष तरीकों को आभासी के रूप में लेबल करके गतिशील बंधन का उपयोग करना चाहिए। डायनेमिक विधि बाइंडिंग ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग के लिए केंद्रीय है।

ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग के लिए तीन मूलभूत अवधारणाओं की आवश्यकता होती है: इनकैप्सुलेशन, इनहेरिटेंस, और डायनेमिक विधि बाइंडिंग।

एनकैप्सुलेशन एक अमूर्त के कार्यान्वयन के विवरण को एक सरल इंटरफ़ेस के पीछे छिपाने की अनुमति देता है।

वंशानुक्रम एक नई अमूर्तता को कुछ मौजूदा अमूर्तता के विस्तार या परिशोधन के रूप में परिभाषित करने की अनुमति देता है, कुछ या सभी विशेषताओं को स्वचालित रूप से प्राप्त करता है।

डायनेमिक मेथड बाइंडिंग नए एब्स्ट्रैक्शन को अपने नए व्यवहार को प्रदर्शित करने की अनुमति देता है, जबकि एक संदर्भ में उपयोग किया जाता है जो पुराने एब्सट्रैक्शन की अपेक्षा करता है।


1

आभासी तरीकों को व्युत्पन्न वर्गों द्वारा ओवरराइड किया जा सकता है, लेकिन बेस क्लास में एक कार्यान्वयन की आवश्यकता होती है (जिसे ओवरराइड किया जाएगा)

शुद्ध आभासी विधियों का आधार वर्ग कोई कार्यान्वयन नहीं है। उन्हें व्युत्पन्न वर्गों द्वारा परिभाषित करने की आवश्यकता है। (इसलिए तकनीकी रूप से ओवरराइड करना सही शब्द नहीं है, क्योंकि ओवरराइड करने के लिए कुछ भी नहीं है)।

वर्चुअल डिफ़ॉल्ट जावा व्यवहार से मेल खाती है, जब व्युत्पन्न वर्ग बेस क्लास की एक विधि को ओवरराइड करता है।

शुद्ध आभासी तरीके अमूर्त वर्गों के भीतर अमूर्त तरीकों के व्यवहार के अनुरूप हैं। और एक वर्ग जिसमें केवल शुद्ध आभासी विधियाँ हैं और स्थिरांक एक अंतरफलक के cpp- लटकन होगा।


0

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

इस कोड को आज़माएं

#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 फ़ंक्शन को आधार वर्ग में आभासी के रूप में चिह्नित किया गया है। यह संकलक कहता है कि व्युत्पन्न वर्ग में फ़ंक्शन की खोज करने और फ़ंक्शन को लागू करने का प्रयास करें। यदि नहीं मिला है, तो आधार को निष्पादित करें। धन्यवाद


हाहा, यह समझने में मुझे 30 सेकंड का समय लगा कि यहाँ क्या गलत है ... हैलो :)
हंस

0

"एक वर्चुअल फंक्शन या वर्चुअल मेथड एक फंक्शन या मेथड है, जिसका व्यवहार एक ही सिग्नेचर वाले फंक्शन द्वारा इनहेरिटिंग क्लास के भीतर ओवरराइड किया जा सकता है" - विकिपीडिया

यह आभासी कार्यों के लिए एक अच्छी व्याख्या नहीं है। क्योंकि, भले ही कोई सदस्य आभासी न हो, विरासत में मिली कक्षाएं इसे ओवरराइड कर सकती हैं। आप इसे स्वयं देख कर देख सकते हैं।

जब फंक्शन एक बेस क्लास को एक पैरामीटर के रूप में लेता है तो अंतर खुद दिखाता है। जब आप इनहेरिटिंग क्लास को इनपुट के रूप में देते हैं, तो वह फ़ंक्शन ओवरराइड फ़ंक्शन के बेस क्लास कार्यान्वयन का उपयोग करता है। हालाँकि, यदि वह फ़ंक्शन वर्चुअल है, तो वह उसी का उपयोग करता है जिसे व्युत्पन्न वर्ग में लागू किया गया है।


0
  • वर्चुअल फ़ंक्शंस की बेस क्लास में परिभाषा होनी चाहिए और व्युत्पन्न वर्ग में भी लेकिन आवश्यक नहीं है, उदाहरण के लिए ToString () या toString () फ़ंक्शन एक वर्चुअल है इसलिए आप इसे उपयोगकर्ता-निर्धारित क्लास (एस) में ओवरराइड करके अपना स्वयं का कार्यान्वयन प्रदान कर सकते हैं।

  • आभासी कार्यों को सामान्य वर्ग में घोषित और परिभाषित किया जाता है।

  • शुद्ध आभासी फ़ंक्शन को "= 0" के साथ समाप्त घोषित किया जाना चाहिए और इसे केवल सार वर्ग में घोषित किया जा सकता है।

  • एक शुद्ध वर्चुअल फ़ंक्शन वाले एक अमूर्त वर्ग में उस शुद्ध वर्चुअल फ़ंक्शंस की कोई परिभाषा नहीं हो सकती है, इसलिए इसका तात्पर्य यह है कि कार्यान्वयन उस वर्ग (वर्ग) में प्रदान किया जाना चाहिए जो उस सार वर्ग से प्राप्त होता है।


@ नोट के रूप में एक ही ध्यान दें: वास्तव में एक शुद्ध आभासी फ़ंक्शन की परिभाषा हो सकती है ...
जेरेक सी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.