C++ Virtual Function

Why we need virtual function?

#include <iostream>
using namespace std;

class Army                         // Class declaration
{
private:
    int numberSuffix;     
    int armyCode;                
protected:
    string name;
public:
    Army(int armycode, int suffix) : name("Shirley") {
         cout << "Super Class:: " << __func__ << endl;     
         enrollment(numberSuffix, armyCode, name);
    }
    void enrollment(int numberSuffix, int armyCode, string name);
    string getPatientName() { 
        cout << "Army " << __func__ << endl;
        return name; 
    }
};

class ArmyHospital : public Army {
public:
    ArmyHospital() : Army(508, 13) {
       name = "Clara";
       cout << "Derived Class: " << __func__ << endl;
    }
    string getPatientName() { 
        cout << "ArmyHospital  " << __func__ << endl;
        return name; 
    }
};

void Army::enrollment(int suffix, int code, string name)
{
     armyCode = code; 
     numberSuffix = suffix;
     cout << "Army::enrollment(), name is " << name << endl;
}

int main() 
{
    Army officer(23, 11);
    cout << "The officer's Name is " << officer.getPatientName() << endl << endl;
    ArmyHospital hospy;
    cout << "The patient's Name is " << hospy.getPatientName() << endl;
    cout << "===========================================" << endl << endl;

    Army* off = new Army(2,1);
    cout << "The 2nd officer's Name is " << off->getPatientName() << endl << endl;
    ArmyHospital* hos = new ArmyHospital;
    cout << "The 2nd patient's Name is " << hos->getPatientName() << endl << endl;
    cout << "===========================================" << endl << endl;

    return 0;
}

Output:

Super Class:: Army
Army::enrollment(), name is Shirley
Army getPatientName
The officer's Name is Shirley

Super Class:: Army
Army::enrollment(), name is Shirley
Derived Class: ArmyHospital
ArmyHospital  getPatientName
The patient's Name is Clara
===========================================

Super Class:: Army
Army::enrollment(), name is Shirley
Army getPatientName
The 2nd officer's Name is Shirley

Super Class:: Army
Army::enrollment(), name is Shirley
Derived Class: ArmyHospital
ArmyHospital  getPatientName
The 2nd patient's Name is Clara

===========================================

There is no problem here, the objects officer and off could call the Army constructors respectively, and so Objects hospy, hos were able to call the ArmyHospital constructors.

It is not necessary to create an object for the parent class because whenever derived class object is created, it will obviously invoke and initialise the members of the parent class. 

Can you tell what happens in the below example.

#include <iostream>
using namespace std;

class Army                         // Class declaration
{
private:
    int numberSuffix;     
    int armyCode;                
protected:
    string name;
public:
    Army(int armycode, int suffix) : name("Shirley") {
         cout << "Super Class:: " << __func__ << endl;     
         enrollment(numberSuffix, armyCode, name);
    }
    void enrollment(int numberSuffix, int armyCode, string name);
    string getPatientName() { 
        cout << "Army " << __func__ << endl;
        return name; 
    }
    void getArmyclass() {
        cout << "Army " << __func__ << endl;
        return; 
    }
};

class ArmyHospital : public Army {
public:
    ArmyHospital() : Army(508, 13) {
       name = "Clara";
       cout << "Derived Class: " << __func__ << endl;
    }
    string getPatientName() { 
        cout << "ArmyHospital  " << __func__ << endl;
        return name; 
    }
    void getArmyclass() {
        cout << "ArmyHospital" << __func__ << endl;
        return; 
    }
};

void Army::enrollment(int suffix, int code, string name)
{
     armyCode = code; 
     numberSuffix = suffix;
     cout << "Army::enrollment(), name is " << name << endl;
}

void mediator(Army *med) {
    cout << __func__ << endl;
    med->getPatientName();
}

int main() 
{
    Army officer(23, 11);
    cout << "The officer's Name is " << officer.getPatientName() << endl << endl;
    ArmyHospital hospy;
    cout << "The patient's Name is " << hospy.getPatientName() << endl;
    cout << "===========================================" << endl << endl;

    Army* off = new Army(2,1);
    cout << "The 2nd officer's Name is " << off->getPatientName() << endl << endl;
    ArmyHospital* hos = new ArmyHospital;
    cout << "The 2nd patient's Name is " << hos->getPatientName() << endl << endl;
    cout << "===========================================" << endl << endl;

    mediator(off);
    mediator(hos);
    return 0;
}

Output:

Super Class:: Army
Army::enrollment(), name is Shirley
Army getPatientName
The officer's Name is Shirley

Super Class:: Army
Army::enrollment(), name is Shirley
Derived Class: ArmyHospital
ArmyHospital  getPatientName
The patient's Name is Clara
===========================================

Super Class:: Army
Army::enrollment(), name is Shirley
Army getPatientName
The 2nd officer's Name is Shirley

Super Class:: Army
Army::enrollment(), name is Shirley
Derived Class: ArmyHospital
ArmyHospital  getPatientName
The 2nd patient's Name is Clara

===========================================

mediator
Army getPatientName  // >>>>>>>>>>>>>>>>>>>>>>>
mediator
Army getPatientName // >>>>>>>>>>>>>>>>>>>>>

Reason

I know you can't get home quickly seeing this complicated example (Laughs). But, please check only mediator function. During the compilation, the decision of which method needs to be called based on the type of the passed pointer, has been taken. This is called "Early Binding"/Static Type. In the below two lines of code, Army is the static type of med.

    mediator(off);
    mediator(hos);

Every variable has a single static type which never changes. Early binding is also called static binding where compiler knows which machine address it has to jump when the function mediator is called. Brush up the binding concept with few minutes read here

During the runtime, the decision of which method needs to be called based on the type of the pointed-to-object, has been taken. This is called "Late Binding"/"Dynamic Type". Dynamic type can change during the program. Dynamic type will be reflected if there is a virtual function in the base class.

In the below two lines of code, Army is the dynamic type of med whereas for the second line, ArmyHospital is the dynamic type of med.  But for both the lines, the static type of med is Army.

    mediator(off);  // Army *med = off;
    mediator(hos);  // Army *med = hos;

Though late-binding is little inefficient, it is widely used with the use of function pointer and virtual. 

Thumb Rule: Instance of derived class can always be substituted for an instance of base class. 

Though this is permitted, it might lose some information if the arguments are passed by value. This problem is called 'Slicing Problem'. This slicing problem will be avoided if pointers(Army *med) are used as in the function mediator. The below diagram depicts the slicing problem if the values are passed by value. 


                   

I again come up with another program which illustrates the same mediator functionality in more simple terms. 

 #include <iostream>
using namespace std;

class Army                         // Class declaration
{
private:
    int numberSuffix_;     
    int armyCode_;                
   
public:
    Army(int armycode, int suffix) {
         //cout << "Parent Class:: " << __func__ << endl;     
    }
   
};

class ArmyHospital : public Army {
private:
    string hospitalName_;
public:
    ArmyHospital(int armycode, int suffix, string name) : Army(armycode, suffix) {
       hospitalName_ = name;
       //cout << "Derived Class: " << __func__ << endl;
    }
};


int main() 
{

    Army* off = new Army(2,1);
  
    ArmyHospital* hos = new ArmyHospital(2, 110, "Rosy");


    /* This is valid as instance of derived class
     * can always be substituted to an instance of 
     * base class. It will not lose information
     */
    off = hos;
    // This is not legal.
    hos = off;
    return 0;
}

Output:

1
2
3
In function 'int main()':
Line 42: error: invalid conversion from 'Army*' to 'ArmyHospital*'
compilation terminated due to -Wfatal-errors.

%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BfillColor%3D%23f5f5f5%3BfontColor%3D%23333333%3BstrokeColor%3D%23666666%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22170%22%20y%3D%22130%22%20width%3D%22120%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%223%22%20value%3D%22%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BfillColor%3D%23f5f5f5%3BfontColor%3D%23333333%3BstrokeColor%3D%23666666%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22170%22%20y%3D%22190%22%20width%3D%22120%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%224%22%20value%3D%22%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BfillColor%3D%23fff2cc%3BstrokeColor%3D%23d6b656%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22170%22%20y%3D%22250%22%20width%3D%22120%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%225%22%20value%3D%22%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BfillColor%3D%23fff2cc%3BstrokeColor%3D%23d6b656%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22370%22%20y%3D%22145%22%20width%3D%22120%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%226%22%20value%3D%22%22%20style%3D%22shape%3DflexArrow%3BendArrow%3Dclassic%3Bhtml%3D1%3Brounded%3D0%3B%22%20edge%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20width%3D%2250%22%20height%3D%2250%22%20relative%3D%221%22%20as%3D%22geometry%22%3E%3CmxPoint%20x%3D%22290%22%20y%3D%22180%22%20as%3D%22sourcePoint%22%2F%3E%3CmxPoint%20x%3D%22370%22%20y%3D%22180%22%20as%3D%22targetPoint%22%2F%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%227%22%20value%3D%22numberSuffix_%22%20style%3D%22text%3Bhtml%3D1%3BstrokeColor%3Dnone%3BfillColor%3Dnone%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22200%22%20y%3D%22145%22%20width%3D%2260%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%228%22%20value%3D%22armyCode_%22%20style%3D%22text%3Bhtml%3D1%3BstrokeColor%3Dnone%3BfillColor%3Dnone%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22190%22%20y%3D%22205%22%20width%3D%2260%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%229%22%20value%3D%22hospitalName_%22%20style%3D%22text%3Bhtml%3D1%3BstrokeColor%3Dnone%3BfillColor%3Dnone%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22200%22%20y%3D%22265%22%20width%3D%2260%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2210%22%20value%3D%22hospitalName_%22%20style%3D%22text%3Bhtml%3D1%3BstrokeColor%3Dnone%3BfillColor%3Dnone%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22400%22%20y%3D%22160%22%20width%3D%2260%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2211%22%20value%3D%22Army%22%20style%3D%22text%3Bhtml%3D1%3BstrokeColor%3D%239673a6%3BfillColor%3D%23e1d5e7%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22190%22%20y%3D%2270%22%20width%3D%2260%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2212%22%20value%3D%22ArmyHospital%22%20style%3D%22text%3Bhtml%3D1%3BstrokeColor%3D%239673a6%3BfillColor%3D%23e1d5e7%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22380%22%20y%3D%2270%22%20width%3D%22100%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphMod


Solution 1

If I want ArmyHospital::getPatientName to be called, I need to create another separate function with ArmyHospital class as argument. But, this doesn't sound great. If this solution is taken, you have to write billions of functions. Okay, You can handle it using templates as well.

void mediator(ArmyHospital *med) {
    cout << __func__ << endl;
    med->getPatientName();
}

Solution 2

If we want to call the derived class function, make the base class function as virtual. That's the solution. Virtual allows the subclass method to be called when derived object is passed. In other words, virtual reacts to the dynamic type of the object it points to at run-time.  Click here to understand the dynamic type with good example.

The version of a method that is executed will be determined by the object that is used to invoke it. If an object of a parent class is used to invoke the method, then the version in the parent class will be executed, but if an object of the subclass is used to invoke the method, then the version in the child class will be executed.

Dispatching 

It is the act of deciding which piece of code to execute when a method is called. 
Static dispatch means that the decision is made statically. (i.e, at Compile time)
Decision made based on static (declared) type of receiver. 
It will call the dynamic type which is also called polymorphic behavior. If the decision is taken at the run time, it is called Dynamic dispatch.

To obtain the dynamic dispatch or polymorphic behavior, the following two conditions should be satisfied. If not, it will be static dispatch. 
  • Dynamic dispatch will not happen if the virtual keyword is not specified in the base class. Click here for override. 
  • Dynamic dispatch will not happen if the object is not accessed through pointer or reference. 

Why C++ doesn't offer virtual behavior by default?

Dynamic dispatch is slightly slower than static dispatch.

Virtual Function

A virtual function is a member function which is declared within a base class and is re-defined(Overrided) by a derived class. 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 ensure that the correct function is called for an object, regardless of the type of reference (or pointer) used for function call.
  • They are mainly used to achieve Runtime polymorphism
  • Functions are declared with a virtual keyword in base class.
  • The resolving of function call is done at Run-time.
Virtual is not a keyword, but modifier. This tells the compiler not to make any decision during compile time but postpone it to run time. 

#include <iostream>
using namespace std;

class Army                         // Class declaration
{

public:
 
    virtual void getPatientName() { 
        cout << "Army " << __func__ << endl;
        return; 
    }

};

class ArmyHospital : public Army {
public:

    void getPatientName() { 
        cout << "ArmyHospital " << __func__ << endl;
        return; 
    }
};



void virtuality(Army *med) {
    cout << __func__ << endl;
    med->getPatientName();
}

int main() 
{
    Army officer;
    cout << "The officer's Name is "; 
    officer.getPatientName();
    ArmyHospital hospy;
    cout << endl << "The patient's Name is ";
    hospy.getPatientName();
    cout << endl << "===========================================" << endl << endl;

    Army* off = new Army;
    cout << "The 2nd officer's Name is ";
    off->getPatientName();
    ArmyHospital* hos = new ArmyHospital;
    cout << endl << endl << "The 2nd patient's Name is ";
    hos->getPatientName();
    cout << endl << "===========================================" << endl << endl;

    virtuality(off);
    virtuality(hos);
    return 0;
}

Output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
The officer's Name is Army getPatientName

The patient's Name is ArmyHospital getPatientName

===========================================

The 2nd officer's Name is Army getPatientName


The 2nd patient's Name is ArmyHospital getPatientName

===========================================

virtuality
Army getPatientName
virtuality
ArmyHospital getPatientName

As shown below, base class pointer can be used to point to Base class object as well as Derived class object. 

 Army* off = new Army(2,1);

When the virtual function is called using a base class pointer (off), the compiler decides at run-time which version of the function to be called. This is also called Runtime Polymorphism.

    mediator(off);
    mediator(hos);


Rules for Virtual Functions

  1. Virtual functions cannot be static.
  2. The keyword virtual should be inside the class declaration. This means the function declaration should be with virtual and can be in the header file, but the function definition can be inside the cpp file. 
  3. A virtual function can be a friend function of another class.
  4. Virtual functions should be accessed using pointer or reference of base class type to achieve run time polymorphism.
  5. The prototype of virtual functions should be the same in the base as well as derived class.
  6. They are always defined in the base class and overridden in a derived class. It is not mandatory for the derived class to override (or re-define the virtual function), in that case, the base class version of the function is used.
  7. A class may have virtual destructor but it cannot have a virtual constructor. It is necessary to have virtual destructor, otherwise we might face consequences.  Check this link here.

Array to objects 

 #include <iostream>
using namespace std;

class Army                         // Class declaration
{
private:
    int numberSuffix_;     
    int armyCode_;                
   
public:
    Army(int armycode, int suffix) {
         cout << "Parent Class:: " << __func__ << endl;     
    }
    virtual
    void warFighting() {
        cout << "Army:" << __func__ << endl;
    }
    virtual
    void treatingPatients() {
        cout << "Army:" << __func__ << endl;
    }
};

class ArmyHospital : public Army {
private:
    string hospitalName_;
public:
    ArmyHospital(int armycode, int suffix, string name) : Army(armycode, suffix) {
       hospitalName_ = name;
       cout << "Derived Class: " << __func__ << endl;
    }
    
    void treatingPatients() {
        cout << __func__ << endl;
    }
};

class ArmySchool : public Army {
private:
    string schoolName_;
public:
    ArmySchool(int armycode, int suffix, string name) : Army(armycode, suffix) {
       schoolName_ = name;
       cout << "Derived Class: " << __func__ << endl;
    }

    void warFighting() {
        cout << __func__ << endl;
    }
};

int main() 
{

    Army off[2];
    off[0] = ArmyHospital(2, 110, "RoseHospital");
    off[1] = ArmySchool(2, 110, "Vladmir Internation School");
    cout << "\n" << "\n";
    for (int i =0; i < 2; i++) {
       off[i].warFighting();
       off[i].treatingPatients(); 
    }
    return 0;
}

The above program needs some tweaking, so wait for me to update this.

Array of pointers to objects 

 #include <iostream>
using namespace std;

class Army                         // Class declaration
{
private:
    int numberSuffix_;     
    int armyCode_;                
   
public:
    Army(int armycode, int suffix) {
         cout << "Parent Class:: " << __func__ << endl;     
    }
   
};

class ArmyHospital : public Army {
private:
    string hospitalName_;
public:
    ArmyHospital(int armycode, int suffix, string name) : Army(armycode, suffix) {
       hospitalName_ = name;
       cout << "Derived Class: " << __func__ << endl;
    }
};

class ArmySchool : public Army {
private:
    string schoolName_;
public:
    ArmySchool(int armycode, int suffix, string name) : Army(armycode, suffix) {
       schoolName_ = name;
       cout << "Derived Class: " << __func__ << endl;
    }
};

int main() 
{

    Army* off[2];
    off[0] = new ArmyHospital(2, 110, "RoseHospital");
    off[1] = new ArmySchool(2, 110, "Vladmir Internation School");

    return 0;
}

Output:
1
2
3
4
Parent Class:: Army
Derived Class: ArmyHospital
Parent Class:: Army
Derived Class: ArmySchool

I created a few functions in the base and derived class, and now I'm gonna call with array of pointers.

 #include <iostream>
using namespace std;

class Army                         // Class declaration
{
private:
    int numberSuffix_;     
    int armyCode_;                
   
public:
    Army(int armycode, int suffix) {
         cout << "Parent Class:: " << __func__ << endl;     
    }
   
    void warFighting() {
        cout << "Army:" << __func__ << endl;
    }
    void treatingPatients() {
        cout << "Army:" << __func__ << endl;
    }
};

class ArmyHospital : public Army {
private:
    string hospitalName_;
public:
    ArmyHospital(int armycode, int suffix, string name) : Army(armycode, suffix) {
       hospitalName_ = name;
       cout << "Derived Class: " << __func__ << endl;
    }
    
    void treatingPatients() {
        cout << __func__ << endl;
    }
};

class ArmySchool : public Army {
private:
    string schoolName_;
public:
    ArmySchool(int armycode, int suffix, string name) : Army(armycode, suffix) {
       schoolName_ = name;
       cout << "Derived Class: " << __func__ << endl;
    }

    void warFighting() {
        cout << __func__ << endl;
    }
};

int main() 
{

    Army* off[2];
    off[0] = new ArmyHospital(2, 110, "RoseHospital");
    off[1] = new ArmySchool(2, 110, "Vladmir Internation School");
    cout << "\n" << "\n";
    for (int i =0; i < 2; i++) {
       off[i]->warFighting();
       off[i]->treatingPatients();
    }
    return 0;
}

Output:
1
2
3
4
5
6
7
8
9
10
Parent Class:: Army
Derived Class: ArmyHospital
Parent Class:: Army
Derived Class: ArmySchool


Army:warFighting
Army:treatingPatients
Army:warFighting
Army:treatingPatients


I wished to call the appropriate derived class objects, but it didn't happen. Since the base class doesn't have virtual, the function called the static type. For the below two lines, the static type of off is Army, and the dynamic type is ArmyHospital & ArmySchool. 

       off[i]->warFighting();
       off[i]->treatingPatients();

Added virtual in the base class now. 

 #include <iostream>
using namespace std;

class Army                         // Class declaration
{
private:
    int numberSuffix_;     
    int armyCode_;                
   
public:
    Army(int armycode, int suffix) {
         cout << "Parent Class:: " << __func__ << endl;     
    }
    virtual
    void warFighting() {
        cout << "Army:" << __func__ << endl;
    }
    virtual
    void treatingPatients() {
        cout << "Army:" << __func__ << endl;
    }
};

class ArmyHospital : public Army {
private:
    string hospitalName_;
public:
    ArmyHospital(int armycode, int suffix, string name) : Army(armycode, suffix) {
       hospitalName_ = name;
       cout << "Derived Class: " << __func__ << endl;
    }
    
    void treatingPatients() {
        cout << __func__ << endl;
    }
};

class ArmySchool : public Army {
private:
    string schoolName_;
public:
    ArmySchool(int armycode, int suffix, string name) : Army(armycode, suffix) {
       schoolName_ = name;
       cout << "Derived Class: " << __func__ << endl;
    }

    void warFighting() {
        cout << __func__ << endl;
    }
};

int main() 
{

    Army* off[2];
    off[0] = new ArmyHospital(2, 110, "RoseHospital");
    off[1] = new ArmySchool(2, 110, "Vladmir Internation School");
    cout << "\n" << "\n";
    for (int i =0; i < 2; i++) {
       off[i]->warFighting();
       off[i]->treatingPatients();
    }
    return 0;
}

Output:
1
2
3
4
5
6
7
8
9
10
Parent Class:: Army
Derived Class: ArmyHospital
Parent Class:: Army
Derived Class: ArmySchool


Army:warFighting
treatingPatients
warFighting
Army:treatingPatients

Some key things to note down.
If both the objects are going to be the different types, then go for the first. If both the objects are same, choose the latter. 

Army *army1[2];
army1[0] = new ArmyHospital();
army1[1] = new ArmySchool();

Army *army1 = new ArmyHospital[2]();

Click here for the usage of double pointers. If the function is present only in the parent class, it doesn't require virtual.

Another reason: Why we need virtual?

In the below problem, I want to get the derived class name or in other words I want to get each instance's brand in base class's member function.

#include <iostream>

class Car {
public:
    Car (std::string color) : color_(color) {}

    std::string getColor() const {
        return color_;
    }

    std::string brand() const {
        std::string res;
        //Tesla - color: Black 
        res += type_;
        res += "color: " + getColor();
        return res;
    }
protected:
        std::string color_;
        std::string type_;
};

class Tesla : public Car {
public:
    Tesla (std::string color) : Car(color) { type_ = "Tesla"; }
};

class Benz : public Car {
public:
    Benz (std::string color) : Car(color) { type_ = "Benz"; }
};

int main()
{
    Tesla t1("Black");
    std::cout << t1.brand() << std::endl;

    return 0;
}

Click here to execute/debug the above program. 

If we simply add variable indicating the 'type_' of car, the the base class might end up look like below while adding another member function in future.

void Car::someFunction() {
     if (type == "Tesla") { }
     else if (type == "Benz") { }
     else if ...
}

We can avoid this by thinking we almost shouldn't do changes in base class if we add another derived class. If we make more changes when the new class is added, we always have the dependency on finding the old code where we need to add the type of the new derived class. This is ridiculous. That's the reason we have inheritance and virtual.

The easiest way is to define a pure virtual function that ought to return the brand as a string(view) in the base class. You can then override this function in the derived classes.

#include <iostream>

class Car {
   public:
    Car(std::string color) : color_(color) {}

    std::string getColor() const { return color_; }

    std::string brand() const {
        std::string res;

        res += "name: ";
        res.append(getName());
        res += ", color: " + color_;
        return res;
    }

    virtual std::string_view getName() const = 0;

   protected:
    std::string color_;
};

class Tesla : public Car {
   public:
    Tesla(std::string color) : Car(color) {}

    virtual std::string_view getName() const override { return "Tesla"; }
};

class Benz : public Car {
   public:
    Benz(std::string color) : Car(color) {}

    virtual std::string_view getName() const override { return "Benz"; }
};

int main() {
    Tesla t1("Black");
    std::cout << t1.brand() << std::endl;

    return 0;
}

Click here to debug or execute this program.


As I'm refreshing  the C++, I planned to record the small details as well. Here, getline. 

#include <iostream>

using namespace std;

int main()
{
    string name; 
    
    //It's important to give the prompt to user for the input
    cout << "Enter the user's name ";
    getline(cin, name);
    cout << "The entered user's name is " << name;
    
}

Output 


References 

https://courses.cs.washington.edu/courses/cse143/00wi/lectures/r-dynamic-dispatch.pdf





Comments