Default arguments & virtual function in C++

Default arguments & virtual function in C++
Default arguments & virtual function in C++

In this article, we will learn about the basic functioning of default arguments and virtual functions following with the participation of default arguments in case of virtual functions.

Let us first understand the basic meanings of both the terms in C++ to get a better understanding of the concept. 

What are default arguments?

The default argument is defined as a value provided in the declaration of the function such that it automatically assigns the values when no argument is passed to it. In case any value is passed the default value is overridden.

Example:

#include<iostream>
using namespace std;
void sum ( int x, int y = 10, int z = 20)
{
	cout << (x+ y+ z); // returns the sum of x, y, z
}
int main()
{
	sum(10); // outputs 40 as x=10, y=10 and z=20
	sum(10, 20, 30); // outputs 60 as x=10, y=20, z=30 
}

Key points to remember for default arguments:

  • When we do function overloading in default arguments the value of parameters should be not ambiguous. This may result in an error.
  • The default values must be to the right of the function as assigning of default values start from right to left.
  • While calling functions the values are assigned from left to right. So, the variables that do not have a default value must be put in left.
  • Default arguments must not be written in both function declaration and function definition. It must only be written in the declaration.

Virtual Function in C++
A virtual function is a member function in the base class that we expect to redefine in derived classes.
Basically, a virtual function is used in the base class to ensure that the function is overridden. This especially applies to cases where a pointer of base class points to an object of a derived class.

Rules for Virtual Functions

  • Virtual functions cannot be static and also cannot be a friend function of another class.
  •  Virtual functions should be accessed using pointer or reference of base class type to achieve run time polymorphism.
  •  The prototype of virtual functions should be the same in the base as well as derived class.
  •  They are always defined in the base class and overridden in the derived class. The derived class doesn’t need to override (or re-define the virtual function), in that case, the base class version of the function is used.
  •  A class may have virtual destructor but it cannot have a virtual constructor.

Example:

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

Later, if we create a pointer of Base type to point to an object of Derived class and call the print() function, it calls the print() function of the Base class. In other words, the member function of Base is not overridden.

int main() {
    Derived derived1;
    Base* base1 = &derived1;
    // calls function of Base class
    base1->print();
    return 0;
}

In order to avoid this, the print() function of the base class is declared as virtual by using the virtual keyword.

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

Now let us learn about the combined problem of virtual functions and default arguments with the help of below example:

#include<iostream>
using namespace std;
class B {
   public:
      virtual void s( int x = 0 ) {
         cout<<" In Base \n";
      }
};
class D: public B {
   public:
      virtual void s(int a = x) {
         cout << "In Derived, x="<<x;
      }
};
int main(void) {
   D d; // An object of class D
   B *b= &d ;// A pointer of type B* pointing to d
   b->s(); // prints"D::s() called"
   return 0;
}

Output:

In Derived, x = 0
In this output, we observe that s() of the derived class is called and the default value of base class s() is used.
Default arguments do not participate in the signature of functions. So signatures of s() in the base class and derived class are considered the same, hence base class’s s() is overridden. The default value is used at the compile time.

When compiler checks that an argument is missing in a function call, it substitutes the default value given. Therefore, in the above program, the value of x is substituted at the compile time, and at the run time, derived class’s s() is called. Value of a is substituted at compile-time and at run time derived class’s s() is called.

Hence, in general, it is a best practice to avoid default values in virtual functions to avoid confusion.

Keen to explore more about C++, check out the best IDEs in C++.

By Mansi Agarwal