Open In App

Why overriding both the global new operator and the class-specific operator is not ambiguous?

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

The below section deals about overload resolution as it helps in the fundamentals of overloading and overriding. 

Predict the output: 

CPP




#include <iostream>
using namespace std;
   
class Gfg {
public:
    void printHello()
    {
        cout << "hello gfg-class specific" << endl;
    }
};
   
void printHello()
{
    cout << "hello gfg-global" << endl;
}
int main()
{
    Gfg a;
    a.printHello();
    printHello();
}


Python3




class Gfg:
    def printHello(self):
        print("hello gfg-class specific")
 
def printHello():
    print("hello gfg-global")
 
if __name__ == "__main__":
    a = Gfg()
    a.printHello()
    printHello()


Output:
hello gfg-class specific
hello gfg-global

How does the compiler differentiates the class-specific function and a global function? To map the function call with the corresponding function definition, the compiler performs the process of name-lookup. This process yields some set of functions that have the same name and they are called candidate functions. If there is more than one candidate function, the compiler performs the argument-dependent lookup process. If this process also yields more than one candidate function, then the process of overload resolution is carried out to select the function that has to be called. If any of the candidate functions is a member function of the corresponding class (static or non-static), it is prepended with an implicit object parameter which represents the object for which they are called and appears before the first of the actual parameters. Predict the output: 

CPP




#include <iostream>
using namespace std;
   
class Gfg {
public:
    Gfg operator+(Gfg& a)
    {
        cout << "class specific + operator" << endl;
        return Gfg(); // Just return some temporary object
    }
};
   
Gfg operator+(Gfg& a, Gfg& b)
{
    cout << "global + operator called" << endl;
    return Gfg(); // Just return some temporary object
}
   
int main()
{
    Gfg a, b;
    Gfg c = a + b;
}


Output: Compilation error
plusOverride.cpp: In function ‘int main()’:
plusOverride.cpp:19:9: error: ambiguous overload for ‘operator+’
(operand types are ‘Gfg’ and ‘Gfg’)
Gfg c=a+b;
^
plusOverride.cpp:19:9: note: candidates are:
plusOverride.cpp:6:9: note: Gfg Gfg::operator+(Gfg&)
Gfg operator+(Gfg& a){
^
plusOverride.cpp:12:5: note: Gfg operator+(Gfg&, Gfg&)
Gfg operator+(Gfg& a, Gfg& b){
^

This is how overload resolution works with operator overloading: The candidate functions for both the unary and binary operators are selected from different scopes. They are 1) member candidates: The operator overloaded functions defined in the class. 2) non-member candidates: The operator overloaded functions that are global. 3) built-in candidates: The built-in functions that perform the specified operation. Hence, for the above program during the compilation, the number of candidate functions is more than one and all these candidate functions have the same precedence and hence the ambiguous overload error arises. Predict the output: 

CPP




#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
   
class Gfg {
public:
    int a;
    void* operator new(size_t sz)
    {
        cout << "class-specific new for size " << sz << '\n';
        return malloc(sz);
    }
   
    void* operator new[](size_t sz)
    {
        cout << "class-specific new[] for size " << sz << '\n';
        return malloc(sz);
    }
};
   
void* operator new[](size_t sz)
{
    cout << "global new[] for size" << sz << '\n';
    return malloc(sz);
}
   
void* operator new(size_t sz)
{
    cout << "global new for size" << sz << '\n';
    return malloc(sz);
}
   
int main()
{
    Gfg* p1 = new Gfg;
    delete p1;
    Gfg* p2 = new Gfg[10];
    delete[] p2;
}


Output: 
class-specific new for size 4
class specific new[] for size 40

The program worked for the following reasons: The C++ standards state that “If a class has a class-specific allocation function, it is the function that will be called, not the global allocation function. This is intentional: the class member is expected to know best how to handle that class”. It means, when the new expression looks for the corresponding allocation function, it begins at class scope before examining the global scope, and if the class-specific new is provided, it is invoked. Else it checks for the global scope and invokes it. If the global scope new function is not present, it will invoke the built-in new function. Henceforth, the candidate functions do not have the same precedence in the above example and hence it compiles without any error. Can the programmer invoke the global new operator even if the class-specific new operator is defined? Yes. C++ provides the scope-resolution operator for that purpose. If the new operator is preceded with the scope resolution(::) operator, the compiler searches for the operator new in the global scope. What happens if the new operator is not defined in the global scope and you are calling the new operator using the :: unary operator? The compiler will invoke the built-in new function. The following example demonstrates how it works. It does contain the class-specific operator new but the global operator new. Henceforth, while invoking ::new, the compiler invokes the standard library new function. 

CPP




#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
   
class Gfg {
public:
    int a;
    void* operator new(size_t sz)
    {
        cout << "class-specific new for size " << sz << '\n';
        return malloc(sz);
    }
   
    void* operator new[](size_t sz)
    {
        cout << "class-specific new[] for size " << sz << '\n';
        return malloc(sz);
    }
};
   
void* operator new[](size_t sz)
{
    cout << "global new[] for size " << sz << '\n';
    return malloc(sz);
}
   
int main()
{
    Gfg* p1 = ::new Gfg;
    cout << "Allocated sie of p1: " << sizeof(*p1) << endl;
    delete p1;
    Gfg* p2 = ::new Gfg[10];
    delete[] p2;
}


Output:
Allocated sie of p1: 4
global new[] for size 40

Why C++ provides this extensibility for new function?

  1. Performance: The built-in memory allocator function is a general purpose function and it fits for predefined data-types. For user-defined data-types that have very specific data to be allocated, and by customizing the way they’re allocated you can speed up memory management considerably.
  2. Debugging & statistics: Possessing the control over the way the memory is being spent provides great flexibility for debugging, statistics and performance analysis.

These are some of the various reasons to make the programming easier while solving complex problems.



Last Updated : 01 Nov, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads