为什么将NULL转换为字符串*?

时间:2010-10-21 18:17:29

标签: c++ templates overloading overload-resolution

我看到了以下代码:

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*)

谢谢

6 个答案:

答案 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)

  1. operator Anything()重载“强制转换”运算符。每当NullClass需要转换为Anything时,将调用此函数,并使用结果。

    在你的情况下,Anything是T*,其中T可以是任何类型(它是模板参数),这意味着NullClass支持转换为任何指针。

  2. 由于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