c++ - सी प्लस प्लस




सी++ में हमें आभासी कार्यों की आवश्यकता क्यों है? (14)

हमें सी ++ में वर्चुअल तरीके क्यों चाहिए?

शीघ्र जवाब:

  1. यह हमें ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग के लिए आवश्यक "अवयवों" में से एक प्रदान करता है।

बजेर्न स्ट्राउस्ट्रप सी ++ प्रोग्रामिंग में: सिद्धांत और अभ्यास, (14.3):

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

  1. यदि आपको वर्चुअल फ़ंक्शन कॉल 2 की आवश्यकता है तो यह सबसे तेज़ और अधिक प्रभावी कार्यान्वयन है।

वर्चुअल कॉल को संभालने के लिए, किसी को व्युत्पन्न ऑब्जेक्ट 3 से संबंधित डेटा के एक या अधिक टुकड़ों की आवश्यकता होती है । आमतौर पर जिस तरह से किया जाता है वह कार्यों की तालिका का पता जोड़ना है। इस तालिका को आमतौर पर वर्चुअल टेबल या आभासी फ़ंक्शन तालिका के रूप में जाना जाता है और इसका पता अक्सर वर्चुअल पॉइंटर कहा जाता है। प्रत्येक वर्चुअल फ़ंक्शन वर्चुअल टेबल में स्लॉट प्राप्त करता है। कॉलर के ऑब्जेक्ट (व्युत्पन्न) प्रकार के आधार पर, वर्चुअल फ़ंक्शन, इसके बदले में, संबंधित ओवरराइड को आमंत्रित करता है।

1. विरासत, रन-टाइम पॉलिमॉर्फिज्म का उपयोग, और encapsulation ऑब्जेक्ट उन्मुख प्रोग्रामिंग की सबसे आम परिभाषा है।

2. आप रन कार्यक्षमता के विकल्पों में से किसी एक को चुनने के लिए अन्य भाषा सुविधाओं का उपयोग करके कार्यक्षमता कोड को किसी भी तेज़ या कम स्मृति का उपयोग नहीं कर सकते हैं। बजेर्न स्ट्राउस्ट्रप सी ++ प्रोग्रामिंग: सिद्धांत और अभ्यास। (14.3.1)

3. जब हम वर्चुअल फ़ंक्शन वाले बेस क्लास को कॉल करते हैं तो यह बताने के लिए कि कौन सा फ़ंक्शन वास्तव में लागू होता है।

मैं सी ++ सीख रहा हूं और मैं सिर्फ आभासी कार्यों में जा रहा हूं।

जो मैंने पढ़ा है (पुस्तक और ऑनलाइन में), वर्चुअल फ़ंक्शंस बेस क्लास में फ़ंक्शन हैं जिन्हें आप व्युत्पन्न कक्षाओं में ओवरराइड कर सकते हैं।

लेकिन पुस्तक में पहले, मूल विरासत के बारे में सीखते समय, मैं virtual उपयोग किए बिना व्युत्पन्न कक्षाओं में आधार कार्यों को ओवरराइड करने में सक्षम था।

तो मैं यहाँ क्या याद कर रहा हूँ? मुझे पता है कि आभासी कार्यों के लिए और भी कुछ है, और यह महत्वपूर्ण लगता है इसलिए मैं स्पष्ट होना चाहता हूं कि यह वास्तव में क्या है। मुझे बस एक सीधा जवाब ऑनलाइन नहीं मिल रहा है।


"आभासी" के बिना आपको "प्रारंभिक बाध्यकारी" मिलता है। विधि के कार्यान्वयन का उपयोग उस पॉइंटर के प्रकार के आधार पर संकलित समय पर तय किया जाता है जिसे आप कॉल करते हैं।

"आभासी" के साथ आपको "देर से बाध्यकारी" मिलता है। विधि का कौन सा कार्यान्वयन उपयोग किया जाता है, बिंदु-बिंदु वस्तु के प्रकार के आधार पर रन टाइम पर निर्णय लिया जाता है - जिसे मूल रूप से बनाया गया था। यह आवश्यक नहीं है कि आप उस ऑब्जेक्ट को इंगित करने वाले सूचक के प्रकार के आधार पर क्या सोचेंगे।

class Base
{
  public:
            void Method1 ()  {  std::cout << "Base::Method1" << std::endl;  }
    virtual void Method2 ()  {  std::cout << "Base::Method2" << std::endl;  }
};

class Derived : public Base
{
  public:
    void Method1 ()  {  std::cout << "Derived::Method1" << std::endl;  }
    void Method2 ()  {  std::cout << "Derived::Method2" << std::endl;  }
};

Base* obj = new Derived ();
  //  Note - constructed as Derived, but pointer stored as Base*

obj->Method1 ();  //  Prints "Base::Method1"
obj->Method2 ();  //  Prints "Derived::Method2"

संपादित करें - यह प्रश्न देखें।

इसके अलावा - इस ट्यूटोरियल में सी ++ में शुरुआती और देर से बाइंडिंग शामिल है।


आपको कम से कम 1 स्तर की विरासत और इसे प्रदर्शित करने के लिए एक डाउनकास्ट की आवश्यकता है। यहां एक बहुत ही सरल उदाहरण है:

class Animal
{        
    public: 
      // turn the following virtual modifier on/off to see what happens
      //virtual   
      std::string Says() { return "?"; }  
};

class Dog: public Animal
{
    public: std::string Says() { return "Woof"; }
};

void test()
{
    Dog* d = new Dog();
    Animal* a = d;       // refer to Dog instance with Animal pointer

    cout << d->Says();   // always Woof
    cout << a->Says();   // Woof or ?, depends on virtual
}

आभासी समारोह की आवश्यकता समझाया [समझने में आसान]

#include<iostream>

using namespace std;

class A{
public: 
        void show(){
        cout << " Hello from Class A";
    }
};

class B :public A{
public:
     void show(){
        cout << " Hello from Class B";
    }
};


int main(){

    A *a1 = new B; // Create a base class pointer and assign address of derived object.
    a1->show();

}

आउटपुट होगा:

Hello from Class A.

लेकिन वर्चुअल फ़ंक्शन के साथ:

#include<iostream>

using namespace std;

class A{
public:
    virtual void show(){
        cout << " Hello from Class A";
    }
};

class B :public A{
public:
    virtual void show(){
        cout << " Hello from Class B";
    }
};


int main(){

    A *a1 = new B;
    a1->show();

}

आउटपुट होगा:

Hello from Class B.

इसलिए वर्चुअल फ़ंक्शन के साथ आप रनटाइम पॉलीमोर्फिज्म प्राप्त कर सकते हैं।


कीवर्ड आभासी संकलक को बताता है कि इसे प्रारंभिक बाध्यकारी नहीं करना चाहिए। इसके बजाए, इसे स्वचालित रूप से देर से बाध्यकारी करने के लिए आवश्यक सभी तंत्र स्थापित करना चाहिए। इसे पूरा करने के लिए, सामान्य कंपाइलर 1 वर्चुअल फ़ंक्शंस वाले प्रत्येक वर्ग के लिए एक एकल तालिका (जिसे VTABLE कहा जाता है) बनाता है। कंपाइलर VTABLE में उस विशेष श्रेणी के लिए वर्चुअल फ़ंक्शंस के पते रखता है। वर्चुअल फ़ंक्शंस वाले प्रत्येक वर्ग में, यह गुप्त रूप से एक पॉइंटर रखता है, जिसे vpointer (जिसे VPTR के रूप में संक्षिप्त किया जाता है) कहा जाता है, जो उस ऑब्जेक्ट के लिए VTABLE को इंगित करता है। जब आप बेस-क्लास पॉइंटर के माध्यम से वर्चुअल फ़ंक्शन कॉल करते हैं तो संकलक चुपचाप वीपीटीआर लाने के लिए कोड डालता है और VTABLE में फ़ंक्शन पता देखता है, इस प्रकार सही फ़ंक्शन को कॉल करता है और देर से बाध्यकारी होता है।

इस लिंक में अधिक जानकारी http://cplusplusinterviews.blogspot.sg/2015/04/virtual-mechanism.html


जब आपके पास बेस क्लास में कोई फ़ंक्शन होता है, तो आप व्युत्पन्न कक्षा में इसे Redefine या Override कर सकते हैं।

एक विधि को फिर से परिभाषित करना : व्युत्पन्न वर्ग में बेस क्लास की विधि के लिए एक नया कार्यान्वयन दिया जाता है। Dynamic binding सुविधा नहीं है

एक विधि ओवरराइड करना : व्युत्पन्न कक्षा में बेस क्लास की virtual method को फिर से Redefining करना। वर्चुअल विधि गतिशील बाध्यकारी की सुविधा प्रदान करता है

तो जब आपने कहा:

लेकिन पुस्तक में पहले, मूल विरासत के बारे में सीखते समय, मैं 'वर्चुअल' का उपयोग किये बिना व्युत्पन्न कक्षाओं में आधार विधियों को ओवरराइड करने में सक्षम था।

आप इसे ओवरराइड नहीं कर रहे थे क्योंकि बेस क्लास में विधि वर्चुअल नहीं थी, बल्कि आप इसे फिर से परिभाषित कर रहे थे


मेरे पास एक बेहतर बातचीत के लिए वार्तालाप के रूप में मेरा जवाब है:

हमें आभासी कार्यों की आवश्यकता क्यों है?

पॉलिमॉर्फिज्म के कारण।

पॉलिमॉर्फिज्म क्या है?

तथ्य यह है कि आधार सूचक भी व्युत्पन्न प्रकार वस्तुओं को इंगित कर सकता है।

पॉलिमॉर्फिज्म की यह परिभाषा वर्चुअल फ़ंक्शंस की आवश्यकता में कैसे जाती है?

खैर, शुरुआती बाध्यकारी के माध्यम से।

प्रारंभिक बाध्यकारी क्या है?

सी ++ में प्रारंभिक बाध्यकारी (संकलन-समय बाध्यकारी) का अर्थ है कि प्रोग्राम निष्पादित होने से पहले एक फ़ंक्शन कॉल तय किया जाता है।

इसलिए...?

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

यदि ऐसा नहीं है कि हम क्या करना चाहते हैं, तो इसकी अनुमति क्यों है?

क्योंकि हमें पॉलिमॉर्फिज्म चाहिए!

तब पॉलिमॉर्फिज्म का क्या फायदा है?

आप किसी एकल फ़ंक्शन के पैरामीटर के रूप में बेस टाइप पॉइंटर का उपयोग कर सकते हैं, और उसके बाद अपने प्रोग्राम के रन-टाइम में, आप किसी भी समस्या के बिना व्युत्पन्न प्रकार इंटरफ़ेस (जैसे उनके सदस्य फ़ंक्शंस) तक पहुंच सकते हैं, उस सिंगल के डिफ्रेंसिंग का उपयोग करके आधार सूचक

मुझे अभी भी पता नहीं है कि वर्चुअल फ़ंक्शन क्या अच्छे हैं ...! और यह मेरा पहला सवाल था!

अच्छा, ऐसा इसलिए है क्योंकि आपने जल्द ही अपने प्रश्न पूछा!

हमें आभासी कार्यों की आवश्यकता क्यों है?

मान लें कि आपने बेस पॉइंटर के साथ एक फ़ंक्शन कहा है, जिसमें किसी ऑब्जेक्ट का पता उसके व्युत्पन्न वर्गों में से एक है। जैसा कि हमने उपरोक्त के बारे में बात की है, रन-टाइम में, इस सूचक को संदर्भित किया जाता है, अब तक इतना अच्छा है, हालांकि, हम एक विधि (== एक सदस्य फ़ंक्शन) "हमारे व्युत्पन्न वर्ग से" निष्पादित होने की अपेक्षा करते हैं! हालांकि, एक ही विधि (जिसकी एक ही शीर्षलेख है) पहले से ही बेस क्लास में परिभाषित है, तो आपका प्रोग्राम अन्य विधि चुनने के लिए परेशान क्यों होना चाहिए? दूसरे शब्दों में मेरा मतलब है, आप इस परिदृश्य को सामान्य रूप से क्या देखते थे, उससे पहले आप कैसे कह सकते हैं?

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

एक अलग कार्यान्वयन क्यों?

तुम नाक-सिर! एक अच्छी किताब पढ़ें!

ठीक है, प्रतीक्षा प्रतीक्षा करें, बेस बेसर्स का उपयोग करने के लिए परेशान क्यों होगा, जब वह व्युत्पन्न प्रकार पॉइंटर्स का उपयोग कर सकता है? आप जज हो, क्या यह सब सिरदर्द इसके लायक है? इन दो स्निपेट को देखो:

// 1:

Parent* p1 = &boy;
p1 -> task();
Parent* p2 = &girl;
p2 -> task();

// 2:

Boy* p1 = &boy;
p1 -> task();
Girl* p2 = &girl;
p2 -> task();

ठीक है, हालांकि मुझे लगता है कि 1 अभी भी 2 से बेहतर है, आप इस तरह 1 लिख सकते हैं:

// 1:

Parent* p1 = &boy;
p1 -> task();
p1 = &girl;
p1 -> task();

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

double totalMonthBenefit = 0;    
std::vector<CentralShop*> mainShop = { &shop1, &shop2, &shop3, &shop4, &shop5, &shop6};
for(CentralShop* x : mainShop){
     totalMonthBenefit += x -> getMonthBenefit();
}

अब, किसी भी सिरदर्द के बिना , इसे फिर से लिखने का प्रयास करें !

double totalMonthBenefit=0;
Shop1* branch1 = &shop1;
Shop2* branch2 = &shop2;
Shop3* branch3 = &shop3;
Shop4* branch4 = &shop4;
Shop5* branch5 = &shop5;
Shop6* branch6 = &shop6;
totalMonthBenefit += branch1 -> getMonthBenefit();
totalMonthBenefit += branch2 -> getMonthBenefit();
totalMonthBenefit += branch3 -> getMonthBenefit();
totalMonthBenefit += branch4 -> getMonthBenefit();
totalMonthBenefit += branch5 -> getMonthBenefit();
totalMonthBenefit += branch6 -> getMonthBenefit();

और वास्तव में, यह अभी तक एक विकसित उदाहरण हो सकता है!


मैं वर्चुअल फ़ंक्शन का एक और उपयोग जोड़ना चाहता हूं हालांकि यह उपर्युक्त उत्तरों के समान अवधारणा का उपयोग करता है लेकिन मुझे लगता है कि इसका उल्लेख उल्लेखनीय है।

वर्टिकल डिस्ट्रक्टर

वर्चुअल के रूप में बेस क्लास विनाशक घोषित किए बिना, नीचे दिए गए इस कार्यक्रम पर विचार करें; बिल्ली के लिए स्मृति साफ नहीं किया जा सकता है।

class Animal {
    public:
    ~Animal() {
        cout << "Deleting an Animal" << endl;
    }
};
class Cat:public Animal {
    public:
    ~Cat() {
        cout << "Deleting an Animal name Cat" << endl;
    }
};

int main() {
    Animal *a = new Cat();
    delete a;
    return 0;
}

आउटपुट:

Deleting an Animal
class Animal {
    public:
    virtual ~Animal() {
        cout << "Deleting an Animal" << endl;
    }
};
class Cat:public Animal {
    public:
    ~Cat(){
        cout << "Deleting an Animal name Cat" << endl;
    }
};

int main() {
    Animal *a = new Cat();
    delete a;
    return 0;
}

आउटपुट:

Deleting an Animal name Cat
Deleting an Animal

यदि बेस क्लास Base , और व्युत्पन्न क्लास Der , तो आपके पास Base *p पॉइंटर हो सकता है जो वास्तव में Der उदाहरण को इंगित करता है। जब आप p->foo(); , अगर foo वर्चुअल नहीं है , तो Base का संस्करण निष्पादित करता है, इस तथ्य को अनदेखा करता है कि वास्तव में एक Der को इंगित करता है। अगर foo वर्चुअल है, p->foo() के "पत्तेदार" ओवरराइड को निष्पादित करता है, पूरी तरह से इंगित करने के लिए आइटम की वास्तविक कक्षा को ध्यान में रखता है। तो आभासी और गैर-वर्चुअल के बीच का अंतर वास्तव में बहुत महत्वपूर्ण है: पूर्व रनटाइम polymorphism , ओओ प्रोग्रामिंग की मूल अवधारणा को अनुमति देता है, जबकि बाद वाला नहीं होता है।


यहां बताया गया है कि मैं न केवल virtual फ़ंक्शंस को समझता हूं, लेकिन उन्हें क्यों आवश्यकता है:

मान लें कि आपके पास ये दो वर्ग हैं:

class Animal
{
    public:
        void eat() { std::cout << "I'm eating generic food."; }
};

class Cat : public Animal
{
    public:
        void eat() { std::cout << "I'm eating a rat."; }
};

आपके मुख्य समारोह में:

Animal *animal = new Animal;
Cat *cat = new Cat;

animal->eat(); // Outputs: "I'm eating generic food."
cat->eat();    // Outputs: "I'm eating a rat."

अभी तक बहुत अच्छा है, ठीक है ना? पशु सामान्य भोजन खाते हैं, बिल्लियों चूहों खाते हैं, बिना virtual

आइए अब इसे थोड़ा बदल दें ताकि eat() को मध्यवर्ती फ़ंक्शन के माध्यम से बुलाया जा सके (केवल इस उदाहरण के लिए एक छोटा कार्य):

// This can go at the top of the main.cpp file
void func(Animal *xyz) { xyz->eat(); }

अब हमारा मुख्य कार्य है:

Animal *animal = new Animal;
Cat *cat = new Cat;

func(animal); // Outputs: "I'm eating generic food."
func(cat);    // Outputs: "I'm eating generic food."

ओह ओह ... हमने एक बिल्ली को func() में पारित किया, लेकिन यह चूहे नहीं खाएगा। क्या आपको func() अधिभारित करना चाहिए, इसलिए यह Cat* लेता है? यदि आपको पशु से अधिक जानवरों को प्राप्त करना है तो उन्हें सभी को अपने func() आवश्यकता होगी।

समाधान Animal वर्ग से वर्चुअल फ़ंक्शन eat() को eat() लिए है:

class Animal
{
    public:
        virtual void eat() { std::cout << "I'm eating generic food."; }
};

class Cat : public Animal
{
    public:
        void eat() { std::cout << "I'm eating a rat."; }
};

मुख्य:

func(animal); // Outputs: "I'm eating generic food."
func(cat);    // Outputs: "I'm eating a rat."

किया हुआ।


आभासी कीवर्ड संकलक को पॉइंटर वर्ग की बजाय ऑब्जेक्ट की कक्षा में परिभाषित विधि कार्यान्वयन को चुनने के लिए मजबूर करता है।

Shape *shape = new Triangle(); 
cout << shape->getName();

उपर्युक्त उदाहरण में, आकार :: getName डिफ़ॉल्ट रूप से कॉल किया जाएगा, जब तक getName () को बेस क्लास आकार में वर्चुअल के रूप में परिभाषित नहीं किया जाता है। यह कंपाइलर को आकार वर्ग के बजाय त्रिकोण वर्ग में getName () कार्यान्वयन की तलाश करने के लिए मजबूर करता है।

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

आखिरकार, वर्चुअल को सी ++ में क्यों जरूरी है, क्यों इसे जावा में डिफ़ॉल्ट व्यवहार नहीं बनाते?

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

रन टाइम पॉलीमोर्फिज्म का समर्थन करने के लिए वर्चुअल फ़ंक्शंस का उपयोग किया जाता है।

यही है, वर्चुअल कीवर्ड कंपाइलर को संकलन समय पर निर्णय (फ़ंक्शन बाध्यकारी) नहीं करने के लिए कहता है , बल्कि रन टाइम के लिए इसे स्थगित करता है "

  • आप कीवर्ड virtual से पहले virtual घोषणा में virtual वर्चुअल कर सकते हैं। उदाहरण के लिए,

     class Base
     {
        virtual void func();
     }
    
  • जब बेस क्लास में आभासी सदस्य फ़ंक्शन होता है, तो बेस क्लास से प्राप्त होने वाली कोई भी कक्षा फ़ंक्शन को उसी प्रोटोटाइप के साथ फिर से परिभाषित कर सकती है यानी कार्यक्षमता को फिर से परिभाषित किया जा सकता है, फ़ंक्शन का इंटरफ़ेस नहीं।

     class Derive : public Base
     {
        void func();
     }
    
  • बेस क्लास पॉइंटर का उपयोग बेस क्लास ऑब्जेक्ट के साथ-साथ व्युत्पन्न क्लास ऑब्जेक्ट को इंगित करने के लिए किया जा सकता है।

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

Here is complete example that illustrates why virtual method is used.

#include <iostream>

using namespace std;

class Basic
{
    public:
    virtual void Test1()
    {
        cout << "Test1 from Basic." << endl;
    }
    virtual ~Basic(){};
};
class VariantA : public Basic
{
    public:
    void Test1()
    {
        cout << "Test1 from VariantA." << endl;
    }
};
class VariantB : public Basic
{
    public:
    void Test1()
    {
        cout << "Test1 from VariantB." << endl;
    }
};

int main()
{
    Basic *object;
    VariantA *vobjectA = new VariantA();
    VariantB *vobjectB = new VariantB();

    object=(Basic *) vobjectA;
    object->Test1();

    object=(Basic *) vobjectB;
    object->Test1();

    delete vobjectA;
    delete vobjectB;
    return 0;
}

We need virtual methods for supporting "Run time Polymorphism". When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class's version of the function.





virtual-functions