Virtual Functions In C++

Virtual Functions In C++

Through the use of examples, we will learn about C++ virtual functions in this article.

A virtual function is a base class member function that we anticipate derived classes may redefine.

A member function that is declared in a base class and redefined (overridden) by a derived class is known as a virtual function. You can call a virtual function for an object of a derived class and have it run the derived class’s version of the function when you refer to an object of a derived class using a pointer or a reference to the base class.

  • Regardless of the type of reference (or pointer) used for the function call, virtual functions make sure that the right function is called for an object.
  • Their primary purpose is to implement runtime polymorphism.
  • In base classes, functions are declared using the virtual keyword.
  • Runtime resolution of function calls is carried out.

Rules of Virtual Functions

  • Static operations cannot be virtual.
  • A friend function of a different class can be a virtual function.
  • To accomplish runtime polymorphism, virtual functions should be accessed using a pointer or reference of the base class type.
  • Virtual functions should have the same prototype in both the base class and any derivations.
  • Always defined in the base class, they are overridden in derived classes. The function from the base class is used when the derived class does not explicitly override (or redefine) the virtual function.
  • Virtual constructors are not permitted in classes, although virtual destructors are permitted.

In order to ensure that the function is overridden, a virtual function is essentially utilized in the base class. This is especially true when a base class pointer points to an object of a derived class.

Consider the code below as an illustration:

class Base {
   public:
    void print() {
        // code
    }
};

class Derived : public Base {
   public:
    void print() {
        // code
    }
};

The print() function of the Base class is called if a pointer of Base type is later created to point to an object of a Derived class and we call it.

To put it another way, Base’s member function is not overridden.

int main() {
    Derived derived1;
    Base* base1 = &derived1;

    // calls function of Base class
    base1->print();

    return 0;
}

We use the virtual keyword to declare the print() function of the Base class as virtual in order to prevent this.

class Base {
   public:
    virtual void print() {
        // code
    }
};

Virtual functions are an integral part of polymorphism in C++. To learn more, check our tutorial on C++ Polymorphism.

Example 1: C++ Virtual Functions

#include <iostream>
using namespace std;

class Base {
   public:
    virtual void print() {
        cout << "Base Function" << endl;
    }
};

class Derived : public Base {
   public:
    void print() {
        cout << "Derived Function" << endl;
    }
};

int main() {
    Derived derived1;

    // pointer of Base type that points to derived1
    Base* base1 = &derived1;

    // calls member function of Derived class
    base1->print();

    return 0;
}

Output

Derived Function

Here, the print() function of Base has been declared to be virtual.

Therefore, even when we use a pointer of a Base type that links to the Derived object derived1, this function is overwritten.

C++ override Identifier

We now have a new identifier override in C++ 11 that is quite helpful for preventing issues when utilizing virtual functions.

The member functions of the derived classes that replace the member function of the base class are specified by this identifier.

For instance,

class Base {
   public:
    virtual void print() {
        // code
    }
};

class Derived : public Base {
   public:
    void print() override {
        // code
    }
};

The following code is used if a function prototype is used in a Derived class but is defined outside of the class:

class Derived : public Base {
   public:
    // function prototype
    void print() override;
};

// function definition
void Derived::print() {
    // code
}

Deploying C++ override

It is easy to make mistakes when declaring the member functions of the derived classes when utilizing virtual functions.

When these errors are made, using the override identifier causes the compiler to show error warnings.

Otherwise, the virtual function will not be overridden and the program will just build.

Some of these potential errors include:

  • incorrectly named functions: For instance, if the overriding function in the derived class is mistakenly named pint whereas the virtual function in the base class is print() ().
  • various return types for functions If the derived class function is of type int, but the virtual function, for example, is of type void
  • functions with various inputs: If the virtual function’s parameters and the functions in the derived classes don’t match.
  • The base class contains no specified virtual functions.

Utilization of C++ Virtual Functions

Assume that Dog and Cat are derived classes from the base class Animal.

Let’s say there is a typedata member for each class. Assume that the initialization of these variables occurs within their respective constructors.

class Animal {
   private:
    string type;
    ... .. ...
    public:
      Animal(): type("Animal") {}
    ... .. ...
};

class Dog : public Animal {
   private:
    string type;
    ... .. ...
    public:
      Animal(): type("Dog") {}
    ... .. ...
};

class Cat : public Animal {
   private:
    string type;
      ... .. ...
    public:
      Animal(): type("Cat") {}
    ... .. ...
};

Let’s say the software mandates that we write two public functions, one for each class:

  • return the type value using getType()
  • print() to display the type value

It would be cumbersome and time-consuming to separately build both of these functions in each class and override them.

Alternately, we could make getType() virtual in the Animal class and then build a solitary, independent print() function that takes an Animal type pointer as a parameter. The virtual function can then be overridden using this lone function.

class Animal {
    ... .. ...
   public:
    ... .. ...
    virtual string getType {...}
};

... .. ...
... .. ...

void print(Animal* ani) {
    cout << "Animal: " << ani->getType() << endl;
}

The code will become clearer, more concise, and less repetitious as a result.

Example 2: C++ Virtual Functions Demonstration

// C++ program to demonstrate the use of virtual function

#include <iostream>
#include <string>
using namespace std;

class Animal {
   private:
    string type;

   public:
    // constructor to initialize type
    Animal() : type("Animal") {}

    // declare virtual function
    virtual string getType() {
        return type;
    }
};

class Dog : public Animal {
   private:
    string type;

   public:
    // constructor to initialize type
    Dog() : type("Dog") {}

    string getType() override {
        return type;
    }
};

class Cat : public Animal {
   private:
    string type;

   public:
    // constructor to initialize type
    Cat() : type("Cat") {}

    string getType() override {
        return type;
    }
};

void print(Animal* ani) {
    cout << "Animal: " << ani->getType() << endl;
}

int main() {
    Animal* animal1 = new Animal();
    Animal* dog1 = new Dog();
    Animal* cat1 = new Cat();

    print(animal1);
    print(dog1);
    print(cat1);

    return 0;
}

Output

Animal: Animal
Animal: Dog
Animal: Cat

In order to avoid repeating the print() code in every class, we have utilized the virtual function getType() and an Animal pointer in this case.

void print(Animal* ani) {
    cout << "Animal: " << ani->getType() << endl;
}

To dynamically construct objects of the Animal, Dog, and Cat classes, we have created three Animal pointers in the main().

// dynamically create objects using Animal pointers
Animal* animal1 = new Animal();
Animal* dog1 = new Dog();
Animal* cat1 = new Cat();
  • The print() method is then invoked with the following pointers:
  • The pointer points to an Animal object when print(animal1) is called. So, print contains the virtual function from the Animal class that is called ().
  • The pointer points to a Dog object when print(dog1) is called. In order to perform the function of Dog inside of print, the virtual function is overridden ().
  • The pointer points to a Cat object when print(cat1) is executed. Consequently, the virtual function is overridden, and print contains the Cat function instead ().

You may like:

Objects and functions In C++

Leave a Reply