下一节将讨论重载解析,因为它有助于重载和重写的基础。
预测输出:
#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++为新函数提供了这种可扩展性?
- 性能:内置的内存分配器函数是通用函数,适用于预定义的数据类型。对于具有非常特定的数据要分配的用户定义的数据类型,通过自定义它们的分配方式,可以显着加快内存管理。
- 调试和统计信息:拥有对内存使用方式的控制,为调试,统计信息和性能分析提供了极大的灵活性。
这些是使编程更容易同时解决复杂问题的各种原因。