Functions Overloading in C++



Functions that cannot be overloaded in C++


In C++, following function declarations cannot be overloaded.
1) Function declarations that differ only in the return type. For example, the following program fails in compilation.
#include<iostream>
int foo() { 
  return 10; 
}

char foo() { 
  return 'a'; 
}

int main()
{
   char x = foo();
   getchar();
   return 0;
}
2) Member function declarations with the same name and the name parameter-type-list cannot be overloaded if any of them is a static member function declaration. For example, following program fails in compilation.
#include<iostream>
class Test {
   static void fun(int i) {}
   void fun(int i) {}   
};

int main()
{
   Test t;
   getchar();
   return 0;
}
3) Parameter declarations that differ only in a pointer * versus an array [] are equivalent. That is, the array declaration is adjusted to become a pointer declaration. Only the second and subsequent array dimensions are significant in parameter types. For example, following two function declarations are equivalent.
int fun(int *ptr);
int fun(int ptr[]); // redeclaration of fun(int *ptr)
4) Parameter declarations that differ only in that one is a function type and the other is a pointer to the same function type are equivalent.
  void h(int ());
  void h(int (*)()); // redeclaration of h(int())
5) Parameter declarations that differ only in the presence or absence of const and/or volatile are equivalent. That is, the const and volatile type-specifiers for each parameter type are ignored when determining which function is being declared, defined, or called. For example, following program fails in compilation with error “redefinition of `int f(int)’ “
Example:
#include<iostream>
#include<stdio.h>
 
using namespace std;
 
int f ( int x) {
    return x+10;
}

int f ( const int x) {
    return x+10;
}

int main() {     
  getchar();
  return 0;
}
Only the const and volatile type-specifiers at the outermost level of the parameter type specification are ignored in this fashion; const and volatile type-specifiers buried within a parameter type specification are significant and can be used to distinguish overloaded function declarations. In particular, for any type T,
“pointer to T,” “pointer to const T,” and “pointer to volatile T” are considered distinct parameter types, as are “reference to T,” “reference to const T,” and “reference to volatile T.” For example, see the example in this comment posted by Venki.
6) Two parameter declarations that differ only in their default arguments are equivalent. For example, following program fails in compilation with error “redefinition of `int f(int, int)’ “
#include<iostream>
#include<stdio.h>
 
using namespace std;
 
int f ( int x, int y) {
    return x+10;
}

int f ( int x, int y = 10) {
    return x+y;
}

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

Function overloading and const keyword

Predict the output of following C++ program.
#include<iostream>
using namespace std;

class Test
{
protected:
    int x;
public:
    Test (int i):x(i) { }
    void fun() const
    {
        cout << "fun() const called " << endl;
    }
    void fun()
    {
        cout << "fun() called " << endl;
    }
};

int main()
{
    Test t1 (10);
    const Test t2 (20);
    t1.fun();
    t2.fun();
    return 0;
}
Output: The above program compiles and runs fine, and produces following output.
fun() called
fun() const called
The two methods ‘void fun() const’ and ‘void fun()’ have same signature except that one is const and other is not. Also, if we take a closer look at the output, we observe that, ‘const void fun()’ is called on const object and ‘void fun()’ is called on non-const object. C++ allows member methods to be overloaded on the basis of const type. Overloading on the basis of const type can be useful when a function return reference or pointer. We can make one function const, that returns a const reference or const pointer, other non-const function, that returns non-const reference or pointer. See this for more details.
What about parameters? Rules related to const parameters are interesting. Let us first take a look at following two examples. The program 1 fails in compilation, but program 2 compiles and runs fine.
// PROGRAM 1 (Fails in compilation)
#include<iostream>
using namespace std;

void fun(const int i)
{
    cout << "fun(const int) called ";
}
void fun(int i)
{
    cout << "fun(int ) called " ;
}
int main()
{
    const int i = 10;
    fun(i);
    return 0;
}
Output:
Compiler Error: redefinition of 'void fun(int)'
// PROGRAM 2 (Compiles and runs fine)
#include<iostream>
using namespace std;

void fun(char *a)
{
  cout << "non-const fun() " << a;
}

void fun(const char *a)
{
  cout << "const fun() " << a;
}

int main()
{
  const char *ptr = "GeeksforGeeks";
  fun(ptr);
  return 0;
}
Output:
const fun() GeeksforGeeks
C++ allows functions to be overloaded on the basis of const-ness of parameters only if the const parameter is a reference or a pointer. That is why the program 1 failed in compilation, but the program 2 worked fine. This rule actually makes sense. In program 1, the parameter ‘i’ is passed by value, so ‘i’ in fun() is a copy of ‘i’ in main(). Hence fun() cannot modify ‘i’ of main(). Therefore, it doesn’t matter whether ‘i’ is received as a const parameter or normal parameter. When we pass by reference or pointer, we can modify the value referred or pointed, so we can have two versions of a function, one which can modify the referred or pointed value, other which can not.
As an exercise, predict the output of following program.
#include<iostream>
using namespace std;

void fun(const int &i)
{
    cout << "fun(const int &) called ";
}
void fun(int &i)
{
    cout << "fun(int &) called " ;
}
int main()
{
    const int i = 10;
    fun(i);
    return 0;
}

Function overloading and return type

In C++ , functions can not be overloaded if they differ only in the return type.
For example, the following program C++ programs fail in compilation.
C++ Program
#include<iostream>
int foo() { 
    return 10; 
}

char foo() {  // compiler error; new declaration of foo()
    return 'a'; 
}

int main()
{
    char x = foo();
    getchar();
    return 0;
}

Does overloading work with Inheritance?

If we have a function in base class and a function with same name in derived class, can the base class function be called from derived class object? This is an interesting question and as an experiment predict the output of the following C++ program.
 
#include <iostream>
using namespace std;
class Base
{
public:
    int f(int i)
    {
        cout << "f(int): ";
        return i+3;
    }
};
class Derived : public Base
{
public:
    double f(double d)
    {
        cout << "f(double): ";
        return d+3.3;
    }
};
int main()
{
    Derived* dp = new Derived;
    cout << dp->f(3) << '\n';
    cout << dp->f(3.3) << '\n';
    delete dp;
    return 0;
}
The output of this program is:
f(double): 6.3
f(double): 6.6 
Instead of the supposed output:
f(int): 6
f(double): 6.6 
Overloading doesn’t work for derived class in C++ programming language. There is no overload resolution between Base and Derived. The compiler looks into the scope of Derived, finds the single function “double f(double)” and calls it. It never disturbs with the (enclosing) scope of Base. In C++, there is no overloading across scopes – derived class scopes are not an exception to this general rule.

Can main() be overloaded in C++?

Predict the output of following C++ program.
#include <iostream>
using namespace std;
int main(int a)
{
    cout << a << "\n";
    return 0;
}
int main(char *a)
{
    cout << a << endl;
    return 0;
}
int main(int a, int b)
{
    cout << a << " " << b;
    return 0;
}
int main()
{
    main(3);
    main("C++");
    main(9, 6);
    return 0;
}   
The above program fails in compilation and produces warnings and errors (See this for produced warnings and errors). You may get different errors on different compilers.
To overload main() function in C++, it is necessary to use class and declare the main as member function. Note that main is not reserved word in programming languages like C, C++, Java and C#. For example, we can declare a variable whose name is main, try below example:
#include <iostream>
int main()
{
    int main = 10;
    std::cout << main;
    return 0;
}
Ouput:
10
The following program shows overloading of main() function in a class.
#include <iostream>
using namespace std;
class Test
{
public:
    int main(int s)
    {
        cout << s << "\n";
        return 0;
    }
    int main(char *s)
    {
        cout << s << endl;
        return 0;
    }
    int main(int s ,int m)
    {
        cout << s << " " << m;
        return 0;
    }
};
int main()
{
    Test obj;
    obj.main(3);
    obj.main("I love C++");
    obj.main(9, 6);
    return 0;
}
The outcome of program is:
3
I love C++
9 6

Comments

  1. This is just a copy from GeeksfromGeeks. Why can't there new content?

    ReplyDelete

Post a Comment

Popular posts from this blog

Smart Pointers in C++ and How to Use Them

Operator Overloading in C++

How would you read in a string of unknown length without risking buffer overflow