📜  为什么覆盖全局 new运算符和特定于类的运算符不会有歧义?

📅  最后修改于: 2021-10-19 05:47:48             🧑  作者: Mango

以下部分涉及重载解析,因为它有助于重载和覆盖的基础知识。
预测输出:

#include 
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();
}
Output:
hello gfg-class specific
hello gfg-global

编译器如何区分特定于类的函数和全局函数?
为了将函数调用映射到相应的函数定义,编译器执行名称查找过程。这个过程产生了一些具有相同名称的函数,它们被称为候选函数。如果有多个候选函数,编译器将执行依赖参数的查找过程。如果此过程也产生多个候选函数,则执行重载决议过程以选择必须调用的函数。
如果任何候选函数是相应类(静态或非静态)的成员函数,则它前面带有一个隐式对象参数,该参数表示调用它们的对象,并出现在第一个实际参数之前。

预测输出:

#include 
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){
     ^

这是重载解析与运算符重载的工作方式:
一元和二元运算符的候选函数是从不同的范围中选择的。他们是
1) 候选成员:类中定义的运算符重载函数。
2) 非成员候选:运算符重载的全局函数。
3) 内置候选:执行指定操作的内置函数。
因此,对于上述程序,在编译过程中,候选函数的数量不止一个,并且所有这些候选函数具有相同的优先级,从而产生了歧义重载错误。
预测输出:

#include 
#include 
#include 
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

该程序的运行原因如下:
C++ 标准声明“如果一个类具有特定于类的分配函数,则将调用该函数,而不是全局分配函数。这是有意为之:班级成员应该最了解如何处理该班级”。这意味着,当 new 表达式寻找相应的分配函数,它在检查全局作用域之前从类作用域开始,如果提供了特定于类的 new,则调用它。否则,它会检查全局范围并调用它。如果全局范围的 new函数不存在,它将调用内置的 new函数。从今以后,候选函数在上面的例子中没有相同的优先级,因此它编译没有任何错误。

即使定义了特定于类的 new运算符,程序员是否可以调用全局 new运算符符?
是的。 C++ 为此提供了作用域解析运算符。如果 new运算符前面有作用域解析 (::) 运算符,则编译器会在全局作用域中搜索运算符new。

如果 new运算符未在全局范围内定义,而您使用 :: 一元运算运算符调用 new运算符,会发生什么情况?
编译器将调用内置的新函数。下面的例子演示了它是如何工作的。它确实包含特定于类的运算符new 但包含全局运算符new。此后,在调用 ::new 时,编译器会调用标准库 new 函数。

#include 
#include 
#include 
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

为什么 C++ 为新函数提供这种可扩展性?

  1. 性能:内置内存分配器函数是一个通用函数,适用于预定义的数据类型。对于具有要分配的非常具体的数据的用户定义的数据类型,通过自定义它们的分配方式,您可以显着加快内存管理。
  2. 调试和统计:控制内存的使用方式为调试、统计和性能分析提供了极大的灵活性。

这些是在解决复杂问题的同时使编程更容易的各种原因。