with - use of virtual function in c++




सी++ आभासी/शुद्ध आभासी समझाया (8)

यदि फ़ंक्शन को वर्चुअल के रूप में परिभाषित किया गया है और यह शुद्ध वर्चुअल के समान है तो इसका वास्तव में क्या अर्थ है?


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

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

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


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

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

टिप्पणियों के मुताबिक, संकलन असफल हो जाएगा या नहीं, संकलक-विशिष्ट है। कम से कम जीसीसी 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 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;
};

इस मामले में एक subclass कुछ विशिष्ट काम करने के लिए 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
 ... 
};

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


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

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

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

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


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

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

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 () को भारतीय मूल के लिए यह भी कहा जाता है

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

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

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

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


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

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

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

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

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


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

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


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

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

#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();
}

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

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

एक और कोड आज़माएं

#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!

}

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





virtual