Warning: Constant TEMPLATEPATH already defined in /home/u667926427/domains/techcodeninja.com/public_html/wp-includes/default-constants.php on line 414
Virtual Function and Polymorphism Backbone of C++ 2024 Guide

Virtual Function and Polymorphism In C++

In the intricate world of C++ programming, virtual functions and polymorphism stand out as powerful tools that elevate the language’s capabilities. Let’s embark on a journey to understand the nuances of these concepts and explore their applications in real-world scenarios.

Concept of Pointer in C++

A pointer is a special type of variable that represents the memory address of a variable rather than its value.

A pointer in C++ is a variable that holds the address of another variable. Pointers are symbolic representations of addresses and they enable programs to simulate call-by-reference as well as to create and manipulate dynamic data structures. Iterating over elements in arrays or other data structures is one of the main uses of pointers.

Here’s how you can use a pointer:

  1. Define a pointer variable: The syntax to define a pointer is datatype *var_name;. For example, int *ptr; Here, ptr can point to an address which holds int data.
  2. Assign the address of a variable to a pointer: You can use the unary operator & which returns the address of that variable. For example, ptr = &var;.
  3. Access the value stored in the address: You can use the unary operator * which returns the value of the variable located at the address specified by its operand. For example, *ptr.

Here’s a simple example of using pointers:

#include <bits/stdc++.h>
using namespace std;

void tech () {
    int var = 20;
    int* ptr;
    ptr = &var;
    cout << "Value at ptr = " << ptr << "\\n";
    cout << "Value at var = " << var << "\\n";
    cout << "Value at *ptr = " << *ptr << "\\n";
}

int main () {
    tech ();
    return 0;
}

In this example, ptr is a pointer to an int and it’s assigned the address of var. When we print *ptr, it gives us the value stored at the address ptr is pointing to, which is the value of var.

Pointers are also used to achieve Call-By-Reference with a Pointer Argument. In C++, by default arguments are passed by value and the changes made in the called function will not reflect in the passed variable. If we wish to modify the original copy directly (especially in passing huge objects or arrays) and/or avoid the overhead of cloning, we use pass-by-reference.

You can learn more about pointers from w3schools.

Polymorphism in C++

Polymorphism is one of the crucial features of OOP. Polymorphism means one name, multiple forms. The different ways of using the same function or operator depending on what they are operating is called polymorphism.

For Example Program

#include <iostream.h> 
#include <conio.h> 
void area(float r) ; 
void area(float l, float b) ; 
void main( ) 
{
float r1, l1, b1 ; 
 clrscr( ) ; 
 cout<< “enter value of r1:” ; cin>>r1 ; 
 cout<< “enter value of l1:” ; cin>>l1 ; 
 cout<< “enter value of b1:” ; cin>>b1 ; 
 cout<< “Area of circle is”<<endl; area(r1) ; 
 cout<< “Area of rectangle is”<<endl ; area(l1, b1) ; 
 getch( ) ; 
} 
void area (float r) 
{
float a=3.14*r*r ; 
 cout<< “Area=”<<a<<endl ; 
} 
void area(float l , float b) 
{ 
 float a1=l*b ; 
 cout<< “Area=”<<a1<<endl ; 
} 

Output: 
 enter value of r1 : 2 
 enter value of l1 : 4 
 enter value of b1 : 6 
 Area of circle is 
 Area = 12.56 
 Area of rectangle is 
 Area = 24

Classification of Polymorphism:

  1. Compile time polymorphism
  2. Run time polymorphism

The overloaded member functions are ‘selected’ for invoking by matching arguments, both type and number. This information is known to the compiler at the compile time and therefore, the compiler can select the appropriate function for a particular call at the compile time itself. This is called early binding or static binding or static linking. Also known as compile-time polymorphism, early binding simply means that an object is bound to its function call at compile time. The example of compile-time polymorphism are

  1. Function Overloading
  2. Operator Overloading

If a member function is selected while a program is running then this is called run time polymorphism. In run-time polymorphism, the function links with a class very late i.e. after compilation therefore, this is called late binding or dynamic binding. This is called dynamic binding because a function is selected dynamically at runtime. For example virtual function

Virtual Function in C++

A virtual function is a member function that is declared with the base class and redefined by a derived class.

Virtual means existing in effect but not in reality. A function is declared virtual by writing the keyword ‘virtual’ in front of the function header. A virtual function uses a single pointer to base class pointer to refer to all the derived objects. Virtual functions are useful when we have number of objects of different classes but want to put them all on a single list and perform operations on them using the same function call.

When we use the same function name in both the base and derived classes, the function in the base class is declared as a virtual function. The virtual function is invoked at run time based on the type of pointer.

For Example Program

#include <iostream.h> 
class B {
public : virtual void show( ) {
cout<< “This is in class B”<<endl ;
} 
} ; // end of class B 

class D1 : public B{
public : void show( ) {
cout<< “This is in class D1”<<endl ; 
}
} ; // end of class D1 

class D2 : public B {
public: void show( ) {
cout<< “This is in class D2”<<endl ;
} 
} ; //end of class D2 

void main( ) {
 B *Ptr ; 
D1 obj1 ; 
D2 obj2 ; 
B objbase ; 
ptr=&objbase ; 
ptr -> show( ) ; 
ptr=&obj1 ; 
ptr -> show( ) ; 
ptr=&obj2 ; 
ptr -> show( ) ; 
}

Output: 
 This is in class B 
 This is in class D1 
 This is in class D2
For Example Program

#include <iostream.h> 
class polygon 
{
protected : int width, height ; 
public : 
void setdata(int a, int b) 
{ width=a; height=b;
} 
virtual int area( ) 
{
return 0 ; 
} 
} ; //end of class polygon 

class rectangle: public polygon 
{ public: 
int area( ) 
{
return (width*height) ; 
} 
 } ; //end of class rectangle 

class triangle: public polygon 
{
public: int area( ) 
{
 return (width*height /z) ; 
} 
} ; //end of class triangle 

void main( ) 
{
rectangle r ; 
triangle t ; 
polygon p ; 
polygon *p1=&c ; polygon *p2=&t ; 
polygon *p3=&p ; 
p1 setdata(4,5) ; 
p2 setdata(4,5) ; 
p3 setdata(4,5) ; 
cout<<p1 area( )<<endl ; 
cout<<p2 area( )<<endl ; 
cout<<p3 area( )<<endl ; 
} 

Output: 
20 
10 
0 

Virtual inside the base class and redefine it in the derived class. But the function
defined inside the base class B is seldom (rarely) used for performing any task. These
functions only serve as placeholders. Such functions are called do-nothing functions or purevirtual functions.

In the above example, ‘=’ sign has nothing to do with the assignment operation, and the value 0 is not assigned anything. This simply informs the compiler that the function will be pure i.e. it will have no definition relative to base class.

It should be noted that a class containing pure virtual function cannot be used to create
objects of its own. Such classes are known as Abstract classes.

Rules for Virtual Functions:

If a function is made a virtual function, we should observe some basic rules that satisfy the compiler requirements:

  • A virtual function must be a member of some class.
  • A virtual function is accessed by using an object pointer.
  • A virtual function must be defined, even though it may not be used.
  • Such a function cannot be a static member. But it can be a friend of another class.
  • There cannot be virtual constructors in a class but there can be virtual destructors.
  • Incrementing or decrementing the base class pointer (pointing derived object) will
    not make it point to the next object of the derived class object.
  • If a virtual function is defined in the base class, it is not compulsory to redefine it in
    the derived class. In such a case, the calls will invoke the base class function.
  • The base pointer can point to any type of the derived object, but vice-versa is not
    true i.e. the pointer to the derived class object cannot be used to point to the base class object.
  • The prototypes of the virtual in the base class and the corresponding member
    function in the derived class must be the same. If not the same, then C++ treats them as overloaded functions (having the same name, and different arguments) thereby the virtual function mechanism is ignored.

Pure Virtual Function in C++

Pure virtual functions are virtual functions with no definition, They start with ‘virtual’ keyword and ends with = 0.

In other words a pure virtual function is a virtual function with no function body. If we delete the body of virtual function then it becomes pure virtual function.

For example,
suppose void show( ) is a virtual function in a class base class, then
virtual void show( ) =0 ; becomes pure virtual function.
such a function are called pure virtual functions.

For Example Program


#include<iostram.h>
#include<conio.h>

class base {                                           // Abstract base class
public: virtual void show() = 0;        // pure virtual function
};

void base::show(){                             // pure virtual definition
cout<<"pure virtual definiton \n";
}
class derived : public base {
public : void show() {
cout<<"Implementation of virtual function in derived class";
}
};

int main() {
base * b;
derive d;
b=&d;
b -> show();
getch();
}

Abstract Class in C++

Abstract class is a class which contains at least one pure virtual function in it. These classes are used to represent general concepts, which can be used as base classes for more concrete classes.

Here are some key points about abstract classes:

  1. Pure Virtual Functions: A pure virtual function (or abstract function) in C++ is a virtual function for which we can have an implementation, but we must override that function in the derived class. If we do not override the pure virtual function in the derived class, then the derived class also becomes an abstract class. A pure virtual function is declared by assigning 0 in the declaration.
  2. Cannot Instantiate Abstract Classes: We cannot create objects of abstract classes. However, we can have pointers and references of abstract class type.
  3. Abstract Class with Constructors: An abstract class can have constructors.

Here’s an example of an abstract class:

#include <iostream>
using namespace std;

class Base { // Abstract class
public:
    virtual void show() = 0; // Pure virtual function
};

class Derived : public Base { // Derived class
public:
    void show() {
        cout << "In Derived \\n";
    }
};

int main(void) {
    Base* bp = new Derived();
    bp->show();
    return 0;
}

In this example, Base is an abstract class with a pure virtual function show()Derived is a class that inherits from Base and overrides the show() function. We can’t instantiate the Base class, but we can create a pointer of type Base that points to an instance of Derived.

Container Class in C++

A class is said to be a container class which is utilized. for the purpose of holding objects in memory or presistent media.

A container class in C++ is a class designed to hold and organize multiple instances of another type (either another class, or a fundamental type). The value the container provides is largely in its ability to help organize and store items that are put inside it.

Container classes generally come in two different varieties

  1. Value containers: These are compositions that store copies of the objects that they are holding (and thus are responsible for creating and destroying those copies)2.
  2. Reference containers: These are aggregations that store pointers or references to other objects (and thus are not responsible for the creation or destruction of those objects).

In C++, containers typically only hold one type of data. For example, if you have an array of integers, it will only hold integers.

Here are some types of container classes in C++

  • Sequence containers: Implement data structures that can be accessed sequentially. Examples include array, vector, deque, forward_list, and list.
  • Associative containers: Implement sorted data structures that can be quickly searched. Examples include set, map, multiset, and multimap.
  • Unordered associative containers: Implement unsorted (hashed) data structures that can be quickly searched. Examples include unordered_set, unordered_map, unordered_multiset, and unordered_multimap.
  • Container adapters: Provide a different interface for sequential containers. Examples include stack, queue, and priority_queue.

Differences between early and late binding in C++

The differences between early and late binding are given below:

Early BindingLate Binding
It is also known as compile time polymorphism. It is called so because compiler selects the appropriate member function for particular function call at the compile time.It is also known as run time polymorphism. It is called so because the appropriate member functions are selected while the program is executing or running.
The information regarding which function to invoke that matches a particular call is known in advance during compilation. That is why it is also called as early binding.The compiler doesn’t know which function to bind with particular function call until program is executed i.e. the function is linked with particular class much later after compilation.
The function call is linked with particular
function at compiler time statically. So, it is also called static binding.
The selection of appropriate function is
done dynamically at run time, so it is also
called dynamic binding..
This type of binding can be achieved using function overloading and operator
overloading.
This type of binding is achieved using
virtual function and base class pointer.

FAQ’s

Are virtual functions essential in every C++ program?

No, virtual functions are not mandatory for every program. Their usage depends on the design and requirements of the software.

How does dynamic binding differ from static binding?

Dynamic binding occurs at runtime, allowing the program to determine the appropriate function based on the object type. Static binding, in contrast, happens at compile time.

Can a class have both virtual and pure virtual functions?

Yes, a class can have a combination of virtual and pure virtual functions. This allows for flexibility in implementation.

What challenges does multiple inheritance pose in C++?

Multiple inheritance can lead to the “diamond problem,” where ambiguity arises in calling functions from multiple inherited classes. Careful design is crucial to mitigate such issues.

How can I optimize the performance of a program using virtual functions?

Techniques like minimizing virtual function calls and optimizing the vtable structure contribute to performance optimization without compromising flexibility.

Conclusion

In conclusion, virtual functions and polymorphism in C++ empower developers to create robust, scalable, and flexible software solutions. Understanding their intricacies and applications is essential for mastering object-oriented programming and enhancing code quality.