📜  为什么同时覆盖全局new运算符和特定于类的运算符不是模棱两可的?

📅  最后修改于: 2021-05-30 09:15:06             🧑  作者: 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运算符符吗?
是的。 C++为此提供了范围解析运算符。如果new运算符前面有作用域resolution(::)运算符,则编译器将在全局范围内搜索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. 调试和统计信息:拥有对内存使用方式的控制,为调试,统计信息和性能分析提供了极大的灵活性。

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

要从最佳影片策划和实践问题去学习,检查了C++基础课程为基础,以先进的C++和C++ STL课程基础加上STL。要完成从学习语言到DS Algo等的更多准备工作,请参阅“完整面试准备课程”