Home

 › 

Articles

 › 

Virtual Function In C++ :What You Need to Know

virtual functions

Virtual Function In C++ :What You Need to Know

Virtual functions are an important subject to understand for programmers working with object-oriented programming (OOP) languages. It’s a key strategy for achieving polymorphism. This helps to enforce encapsulation and makes our code more effective and able to be used again.

Virtual functions are used by numerous OOP languages, but today we’re talking about C++. Without further ado, let’s discuss the C++ virtual function, its implementation, and how it functions.

What Are Virtual Functions In C++?

Simply put, a virtual function is a member of a class, the base class, which gets overridden by a function with the same name in a derived subclass. This allows polymorphism, as well as abstraction and inheritance. Below is a brief rundown of these terms.

  • Polymorphism: This is where objects of different classes can be treated as if they belong to the same class. A single method can be used to operate on these objects at different times, and is usually combined with inheritance.
  • Inheritance: When a modified derived class takes on properties from a parent class, this is called inheritance. In this way, polymorphism is often achieved through inheritance, but can also be achieved through abstraction or interfaces.
  • Abstraction: This is where details we don’t need are ignored, and it’s often done through the use of abstract classes and interfaces. Abstract classes act as a template and have no implementation within them. They merely provide properties and methods to be inherited and used with a function. An interface, however, is a collection of methods to be implemented, often by unrelated classes.

We can see that polymorphism is usually achieved through inheritance or abstraction, where an abstract class must contain at least one “pure” virtual function (a function with no implementation). For example, consider a class called “Shape.”

This might have a pure virtual function known as “height()”, which isn’t implemented in this class. This is intended to be overridden by a derived class, such as “Square,” “Triangle,” or “Circle.”

In essence, the difference between a pure virtual function and a non-pure virtual function is that a non-pure function can have an implementation in the base class, whereas a virtual function cannot. However, both are virtual, so they can theoretically be overridden by a derived class.

What Are Virtual Functions Used For?

As virtual functions are called by a pointer or object reference, the actual function used depends on the object type, which allows for objects of different types to be operated on consistently. As previously mentioned, virtual functions are mostly used to achieve polymorphism.

This is useful when dealing with a large collection of objects, where the object types may be unknown at runtime. Virtual functions are also helpful for creating class hierarchies, with each derived class having its own unique implementation. Code can then be written that applies to all of these, making it more flexible, reusable, and scalable.

How Are Virtual Functions Implemented?

We often rely on keywords to use functions in C++. And virtual functions are no different. To declare a virtual function, we use the “virtual” keyword. Continuing with our shape example, consider the following code:

#include <iostream>

using namespace std;

class Shape {
public:
    virtual double area() const = 0;
    virtual ~Shape() {}
};

class Rectangle : public Shape {
private:
    double width;
    double height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    double area() const override {
        return width * height;
    }
};

class Circle : public Shape {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    double area() const override {
        return 3.14 * radius * radius;
    }
};

int main() {
    Shape* s1 = new Rectangle(5, 10);
    Shape* s2 = new Circle(7);

    cout << "Area of rectangle: " << s1->area() << endl;
    cout << "Area of circle: " << s2->area() << endl;

    delete s1;
    delete s2;

    return 0;
}

Explanation of Code

To begin, we include the standard input/output library, and declare the standard namespace. We then define a “Shape” base class, with a pure virtual function “area().” Therefore, the “Shape” class is an abstract class with no instances.

A virtual destructor (used to release memory once a class object is destroyed) called “virtual ~Shape() {}” is defined, to be called when objects are deleted through a base class pointer.

Derived classes are then defined as “Rectangle” and “Circle,” along with their private member variables. These are “width” and “height” for the “Rectangle” class, and “radius” for the “Circle” class.

These are initialized with a constructor and intended to override the base “area()” function in order to calculate the areas of these shapes. The main “int main()” function is defined after this, which creates the objects “s1” and “s2”, pointing to “Rectangle” and “Circle.”

Memory is then dynamically allocated for these shapes, and pointers are returned to the parent class. The areas are then printed, and the objects pointed to by these pointers are deleted. The output can be seen in the below image.

virtual function
Calculating the areas of “Rectangle” and “Circle.”

All in all, this code is an example of both pure and non-pure virtual functions. The “area()” function is pure, while the “virtual ~Shape()” function is a non-pure virtual destructor function.

What Is Early and Late Binding?

Binding is when a function call is associated with a function definition. This can happen either at runtime or compile time, and is known as late or early, respectively. In the case of virtual functions, binding is late, as this allows an object type to be dynamic.

In this way, the function is determined depending on the object type, instead of the pointer type. Early binding mostly occurs when using static non-virtual functions, where the object type doesn’t change during execution.

Wrapping Up

To conclude, virtual functions are a key principle in C++, often used to achieve polymorphism. Binding can be done dynamically, meaning the actual function used is determined by object rather than pointer type.

Pure virtual functions and abstract classes are used to enable polymorphic behavior, but abstraction can also be used to create interfaces for this purpose. Whenever using virtual functions, a virtual destructor must be used to delete objects that have been allocated.

Frequently Asked Questions

What are virtual functions?

A virtual function is a function belonging to a class that can be overridden by a derived class. This is often used to allow for polymorphic behavior.

What's the difference between virtual and non-virtual functions?

Where virtual functions are designed to be overridden by subclasses, non-virtual functions can be implemented from within their class. Non-virtual functions can’t be overridden. When a non-virtual function with the same name is called, the base class function will always be called.

What's the difference between pure and non-pure virtual functions?

A pure virtual function has no implementation in its base class, which would be defined as an abstract class with no instances. On the other hand, a non-pure virtual function has a default implementation in its base class, but can also be overridden by derived classes.

How are virtual functions in C++ implemented?

Virtual functions are implemented using vtables, which are a table of pointers used to resolve a call to a virtual function. These are invisible to the code. The vtable pointer of an object is used to find the corresponding function to be called. Each class containing a virtual function will have its own vtable.

 

 

 

 

What are early and late binding?

Early binding is when a function’s implementation is determined at compile time, based on an object type that is static. Late binding, however, is when the implementation is determined at runtime, and works with dynamic object types. Late binding is permitted by virtual functions.

Why can virtual constructors not be used?

C++ does not support virtual constructors, because they’re used to initialize a class object. The virtual function is not set up yet, so this doesn’t work.

Can you use abstract classes without creating interfaces?

Yes, while abstract classes are often used to create interfaces, they can be used to achieve polymorphic behavior without doing so.

What are the advantages of virtual functions?

Virtual functions are a great way to achieve polymorphism, as well as flexible and scalable code. They’re also used to allow loose coupling, where a calling function relies on the base class pointer for its implementation. This minimizes the interaction between components, making them easier to change and the system more robust.

 

What are the limitations of virtual functions?

Virtual functions can lead to reduced performance due to the need for looking up the implementation in the vtable. They can also require a lot of memory to store vtables, and potentially make the code more complex, as memory must be accessed to determine implementation. Generally, however, this is outweighed by the benefits of loose coupling and polymorphism.

To top