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