当传递NULL作为参数时,函数重载是如何工作的

How does function overloading work when passing NULL as argument?

本文关键字:何工作 工作 重载 函数 NULL 参数      更新时间:2023-10-16

我知道NULL被#定义为0。它似乎是一个被转换为指针类型的int常量。那么,当有两个重载函数时会发生什么呢:一个采用指针类型,另一个采用int类型。与nullptr相比,这是如何工作的?

#include <iostream>
using namespace std;
void callMe(int* p)
{
cout << "Function 1 called" << endl;
}
void callMe(int i)
{
cout << "Function 2 called" << endl;
}
int main()
{
callMe(nullptr);
callMe(NULL);
return 0;
}

我知道callMe(nullptr)肯定会调用第一个函数。但是callMe(NULL)将调用哪个函数?我在电脑上编译了这些代码。只有一个警告。

g++ -std=c++11 nullptr_type.cpp
nullptr_type.cpp: In function 'int main()':
nullptr_type.cpp:44:14: warning: passing NULL to non-pointer argument 1 of 'void callMe(int)' [-Wconversion-null]
callMe(NULL);
^

我的代码编译得没有任何问题,当我运行它时,我看到callMe(NULL)调用了函数2。Visual Studio还编译代码并调用函数2。

然而,当我尝试在GeeksForGeeksIDE上编译代码时,我会遇到一些编译器错误。

https://ide.geeksforgeeks.org/UsLgXRgpAe

我想知道为什么会出现这些错误。

prog.cpp: In function 'int main()':
prog.cpp:17:13: error: call of overloaded 'callMe(NULL)' is ambiguous
callMe(NULL);
^
prog.cpp:4:6: note: candidate: void callMe(int*)
void callMe(int* p)
^
prog.cpp:9:6: note: candidate: void callMe(int)
void callMe(int i)
^

在线Ideone IDE和在线TutorialsPoint CodingGround IDE也会产生相同的错误。这是否真的定义了行为?

这个场景怎么样?这里将调用哪些函数?

#include <iostream>
using namespace std;
void callMe(int* p)
{
cout << "Function 1 called" << endl;
}
void callMe(char* cp)
{
cout << "Function 2 called" << endl;
}
void callMe(nullptr_t np)
{
cout << "Function 3 called" << endl;
}
void callMe(int i)
{
cout << "Function 4 called" << endl;
}
int main()
{
callMe(nullptr);
callMe(NULL);
return 0;
}

这是一个更普遍的问题,但我认为这就是一切的发展方向:当重载函数时,你如何知道哪些函数调用是不明确的我想知道这个问题的答案,因为有多个函数是这个论点的竞争对手。如果只有一个函数,那么它将毫无错误地接受参数。但是,当几个函数似乎同样有可能接受这个论点时,会发生什么呢?

链接的问题是关于在C中使用NULL。我的问题是有关C++的。C编程语言没有运算符重载,因此我所涉及的大多数问题都只是C++特定的问题。

=================================================

这是一个相关的问题,它详细解释了这个问题及其解决方案。这里面有很多有用的答案。

使用nullptr的优点是什么?

我知道NULL被#定义为0。

这通常不是真的,它可以定义为nullptr。可能是CCD_ 9。还有其他可能性,例如,我尝试将gcc的一个版本定义为__null,这显然是gcc的空指针常量扩展。

在重载函数时,如何知道哪些函数调用是不明确的?

通过阅读C标准的过载分辨率部分。这是它最复杂的部分之一。简而言之,对不同的转换序列进行排序,并且某些转换序列的排序比其他转换序列高。这里有一个关于cppresence的介绍。

  • callMe(0)解析为(int),因为"精确匹配"优于"转换"。(调用(int *)版本需要整数到指针的转换)
  • callMe(nullptr)解析为(int *),因为从nullptrint甚至没有任何可用的转换
  • callMe(NULL)取决于NULL的定义方式。如果是0nullptr,请参见上文。如果是0L,则它是不明确的,因为需要Conversion来匹配任意一种情况,并且整数转换与整数到指针转换具有相同的秩。等等

我知道NULL被#定义为0

这不是标准所能保证的。NULL可以是任何有效的空指针文字,包括00Lnullptr

然而,如果我们假设标准库实现的情况是NULL实际上被定义为0,那么重载解析的行为将与传递文本0时的行为完全相同。

它似乎是一个转换为指针类型的int常量。

0实际上既是int又是指针常量。但是,如果存在冲突,int是过载解决(以及模板参数检测)的首选。

但是callMe(NULL)将调用哪个函数?

是否定义了实现,具体取决于NULL的定义方式。

在重载函数时,如何知道哪些函数调用是不明确的?

知道函数调用是否不明确的先决条件是知道用作参数的表达式的类型。由于NULL表达式的类型是由实现定义的,因此在某些情况下,实现会以不同的方式解决重载,或者由于歧义而无法解决。

在您知道表达式类型的情况下,标准规则会准确地告诉您何时调用不明确,以及何时一个重载优先于另一个重载。不过,超载规则相当复杂,而且有相当多的规则。该标准的第[over]节应该是最相关的。

[over.match.valid]:从为给定上下文构建的候选函数集([over.match.funcs])中,选择一组可行函数,通过比较参数转换序列和相关约束([temp.contr.dell])以获得最佳拟合([over.match.best]),从中选择最佳函数

[over.best.ics]…如果使用不明确转换序列的函数被选为最佳可行函数,则该调用将是不正确的,因为该调用中某个参数的转换是不明确的。