我看到了以下代码:
class NullClass {
public:
template<class T> operator T*() const { return 0; }
};
const NullClass NULL;
void f(int x);
void f(string *p);
f(NULL); // converts NULL to string*, then calls f(string*)
Q1&GT;我有问题要理解以下陈述
template<class T> operator T*() const { return 0; }
特别是operator T*()
的含义是什么?
Q2&GT;为什么f(NULL)
最终会触发f(string*)
?
谢谢
答案 0 :(得分:11)
operator T*()
的含义是什么?
它是用户定义的转换运算符。它允许将NullClass
类型的对象转换为任何指针类型。
此类转换运算符通常会导致细微,意外和有害的问题,因此在大多数情况下最好避免使用它们(当然,它们偶尔会有用)。
为什么
f(NULL)
最终会触发f(string*)
?
NULL
的类型为NullClass
。它无法转换为int
,但可以使用用户定义的转化NullClass -> T*
将其转换为string*
,因此会选择void f(string*)
。
请注意,这是有效的,因为f
只有一个带有指针的重载。如果你有两个重载,
void f(int*);
void f(float*);
调用不明确,因为NullClass -> T*
转换可以转换为int*
和float*
。
答案 1 :(得分:2)
template<class T> operator T*()
表示任何NullClass
都会从T*
隐式转换为T
。
当您调用f(NULL)
时,编译器需要决定使用哪个重载。由于过载都不会占用NullClass
类型的对象,因此它会查找存在哪些隐式转换。没有转化为int
,但有一个转换为string*
,因此应用转化并调用string*
重载。
答案 2 :(得分:2)
operator Anything()
重载“强制转换”运算符。每当NullClass需要转换为Anything时,将调用此函数,并使用结果。
在你的情况下,Anything是T*
,其中T可以是任何类型(它是模板参数),这意味着NullClass支持转换为任何指针。
由于NullClass可以转换为任何指针,包括string*
。因此将使用f(string*)
版本。
答案 3 :(得分:2)
Q1&GT;我有问题要理解以下陈述
template<class T> operator T*() const { return 0; }
特别是
operator T*()
的含义是什么?
这是一个隐式转换运算符。它使得它所属类型的对象可以隐式转换为目标类型T*
。此版本是一个特殊版本,因为作为模板,它可以将NullClass
的对象转换为 任何 指针类型。
由于充分的理由,隐含的转换是不受欢迎的。他们有在不寻常的时刻踢的坏习惯,使编译器调用一个重载函数的非预期版本。拥有一个模板化的隐式转换运算符尤其邪恶,因为模板化会增加可能性。
Q2&GT;为什么f(NULL)最终触发f(string *)?
见上文。无法转换为int
,因此隐式转换运算符会启动并将NullClass
对象转换为请求的任何指针。
我想这是有意的。通常您不希望将指针转换为整数,这就是为什么该类隐式转换为任何指针,但没有指向int
。
那NullClass
并不是那么糟糕,但NULL
实例却是纯粹的愚蠢。只要包含定义NULL
宏(定义为0
,即整数常量)的许多标头中的任何一个,预处理器将遍历所有源并替换{{1的每个用法与NULL
一起使用。由于你不能避免包括这个,这个错误使整个类几乎没用。
答案 4 :(得分:1)
NuLLClass提供转换函数以转换为指针。当你调用f(NULL)
时,它会尝试找到一种方法将NULL转换为f的有效参数。
因为你可以在NULL上调用operator T*()
,它将使用T = string。这满足了f(string *)
的需求。由于无法将NULL转换为int,因此只能选择要调用的函数。
答案 5 :(得分:1)
特别是
operator T*()
的含义是什么?
这是一个输入T*
的转换运算符。它允许(T*)NULL
等操作。
Q2&GT;为什么f(NULL)最终触发f(string *)?
因为编译器在参数和方法的签名之间寻找最佳匹配,所以在这种情况下选择template<typename T> NullClass::operator T*()
,其中T=string
。