4

我看到了以下代码:

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> 我在理解以下语句时有问题

template<class T> operator T*() const { return 0; }

特别是 是什么意思operator T*()

Q2> 为什么f(NULL)终于触发了f(string*)

谢谢

4

6 回答 6

11

是什么意思operator T*()

它是一个用户定义的转换运算符。它允许将类型对象NullClass转换为任何指针类型。

这种转换运算符通常会导致微妙的、意想不到的和有害的问题,因此在大多数情况下最好避免使用它们(当然,它们偶尔有用)。

为什么f(NULL)终于触发了f(string*)

NULL是类型NullClass。不能转成a int,但是可以通过用户自定义的转换NullClass -> T*来转成a string*,所以void f(string*)被选中。

请注意,这是有效的,因为只有一个重载f需要一个指针。如果你有两个重载,

void f(int*);
void f(float*);

该调用将是模棱两可的,因为NullClass -> T*转换可以同时转换为int*float*

于 2010-10-21T18:20:08.473 回答
2

template<class T> operator T*()意味着对于 any存在从NullClassto的隐式转换。T*T

当您调用f(NULL)时,编译器需要决定使用哪个重载。由于两个重载都不接受 type 的对象NullClass,因此它会查看存在哪些隐式转换。没有到 的转换int,但有一个到string*,因此应用了转换并string*调用了重载。

于 2010-10-21T18:20:06.647 回答
2
  1. operator Anything()重载“cast”运算符。每当需要将 NullClass 转换为任何东西时,都会调用此函数,并使用结果。

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

  2. 由于 NullClass 可以转换为任何指针,包括string*. 因此f(string*)将使用该版本。

于 2010-10-21T18:20:41.910 回答
2

Q1> 我在理解以下语句时有问题

template<class T> operator T*() const { return 0; }

特别是 是什么意思operator T*()

这是一个隐式转换运算符。它可以将其所属类型的对象隐式转换为T*此处的目标类型。这个版本是一个特殊的版本,因为作为一个模板,它可以将一个对象转换NullClass任何指针类型。
有充分的理由不赞成隐式转换。他们有在意想不到的时刻启动的坏习惯,使编译器调用重载函数的意外版本。拥有一个模板化的隐式转换运算符尤其邪恶,因为模板化增加了可能性。

Q2> 为什么 f(NULL) 最终触发了 f(string*)?

往上看。不可能转换为int,因此隐式转换运算符启动并将NullClass对象转换为请求的任何指针。
我想这是故意的。通常您不希望将指针转换为整数,这就是为什么该类隐式转换为任何指针,但没有转换为int.


NullClass并不是那么糟糕,但NULL它的例子是纯粹的愚蠢。只要您包含定义NULL宏的许多标头中的任何一个(定义为0,即整数常量),预处理器就会遍历所有源并替换NULLwith的每个用法0。由于您无法避免包含此错误,因此此错误会使整个课程几乎毫无用处。

于 2010-10-21T18:38:01.420 回答
1

NuLLClass 提供了转换函数来转换为指针。当您调用 时f(NULL),它会尝试找到一种方法将 NULL 转换为 f 的有效参数。

因为你可以调用operator T*()NULL,所以它会使用 T=string。这样就满足了需求f(string *)。由于无法将 NULL 转换为 int,因此只有一个明确的选择来调用哪个函数。

于 2010-10-21T18:21:04.307 回答
1

特别是 是什么意思operator T*()

它是类型的转换运算符T*。它允许诸如(T*)NULL.

Q2> 为什么 f(NULL) 最终触发了 f(string*)?

因为编译器会寻找参数和方法签名之间的最佳匹配,所以在这种情况下选择template<typename T> NullClass::operator T*(), where T=string

于 2010-10-21T18:22:04.653 回答