C++为什么覆盖全局new操作符和类特定操作符不会产生歧义?
下面一节讨论重载决议,因为它有助于重载和覆盖的基础知识。
预测输出:
#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();
}
class Gfg:
def printHello(self):
print("hello gfg-class specific")
def printHello():
print("hello gfg-global")
if __name__ == "__main__":
a = Gfg()
a.printHello()
printHello()
**输出:**
hello gfg-class specific
hello gfg-global
编译器如何区分类特定函数和全局函数? 为了将函数调用与相应的函数定义进行映射,编译器执行名称查找过程。这个过程产生了一些具有相同名称的函数,它们被称为候选函数。如果有多个候选函数,则编译器执行参数相关的查找过程。如果这个过程也产生多个候选函数,则进行重载决议过程,选择要调用的函数。如果任何一个候选函数是相应类的成员函数(静态或非静态),则它会被预设一个隐式对象参数,该参数代表它们被调用的对象,并出现在实际参数的第一个之前。
预测输出:
# 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;
}
**输出:编译错误**
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)内置候选函数:执行指定操作的内置函数。因此,在上面的程序中,在编译期间,候选函数的数量大于1,同时 所有这些候选函数具有相同的优先级 ,因此会产生歧义的重载错误。
预测输出:
#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;
}
输出:
类特定的size 4
类特定的size 40
程序之所以能正常运行的原因是: C++标准规定,“如果一个类具有类特定的分配函数,则调用该函数,而不是全局的分配函数。 这是有意的:类成员应该最了解如何处理该类”。这意味着,当new表达式寻找相应的分配函数时,它从类作用域开始,然后检查全局作用域,如果提供了类特定的新分配函数,则调用它。否则,它将检查全局范围并调用它。如果全局范围中不存在new函数,则会调用内置的new函数。因此,在上面的示例中, 候选函数的优先级不同 ,因此可以编译而不出现任何错误。 程序员是否可以在定义了类特定new运算符的情况下调用全局new操作符? 是的。C++为此提供了作用域解析运算符。如果new运算符前面带有作用域分辨率(::)运算符,则编译器会在全局作用域中搜索operator new。 如果未在全局作用域中定义new运算符,并且您正在使用::单目运算符调用new运算符会发生什么? 编译器将调用内置的new函数。下面的示例演示了其工作原理。它确实包含类特定的new运算符,但是全局运算符new。因此,在调用::new时,编译器会调用标准库new函数。 C++为什么提供了这种新函数的可扩展性?
- 性能: 内置的内存分配器函数是通用型函数,适用于预定义的数据类型。对于具有非常特定数据需要分配的用户定义数据类型,通过定制它们被分配的方式,可以大大加快内存管理的速度。
- 调试和统计: 对内存使用方式的控制为调试、统计和性能分析提供了极大的灵活性。