在C++11中,dynamic_cast返回nullptr还是0?

7

我想检查 dynamic_cast 的结果,在 C++11 (或者对于支持 nullptr 的编译器使用 C++0x),我应该将其与 nullptr 还是 0 进行比较?

这是否重要,如果重要的话,为什么?

结果是否取决于编译器?

2个回答

13

常量nullptr(类型为nullptr_t)和常量0都可以隐式转换为任何指针类型的空值。因此,对它们任意一个进行比较都是可以的,并且在技术上是正确的。顺便说一下,这意味着dynamic_cast不返回任何一个,它会返回特定指针类型的空值。

最好养成使用nullptr而非0的习惯。据我所知,只有在正确的重载决议(例如,其中一个重载接受int,另一个接受char*)时才真正需要使用0。为了保持一致,避免使用0是最好的。

我所说的“指针类型的空值”是什么意思?

考虑变量char * ptr。它的类型是(毫不意外地)char *。但nullptr的类型是特殊类型nullptr_t。因此,当我们写ptr = nullptr时,一些技术细节必须发生:

  1. nullptr必须隐式转换为char *
  2. 将这个转换的结果设置为ptr的新值。

char *的空值是将nullptr转换为char *的结果。在概念上,它仍然是nullptr,但是类型不同(char *)。这个空值与int *string *或任何其他指针类型的空值是不同的。我们往往认为这些空值只是nullptr(或0),但实际上每一个都是一个来自不同类型的不同值。(顺便说一下,使用==进行比较时也会发生相同的转换。)

尽管这听起来像是琐碎的细节,但在重载决议中非常重要:

void foo(char * ptr) { ... }
void foo(int i) { ... }
void foo(nullptr_t ptr) { ... }

int main()
{
    foo(0); // Calls void foo(int), since 0 is an int
    foo(nullptr); // Calls void foo(nullptr_t), since nullptr is a nullptr_t
    foo(new char('c')); // Calls void foo(char *), since new char('c') is a char*
}

或在分配不相关的空值时:

char * c_ptr = nullptr; // Okay
int * i_ptr1 = nullptr; // Okay
int * i_ptr2 = c_ptr;   // COMPILER ERROR HERE

你能定义一下指针类型的空值是什么意思吗?这与0或nullptr有何不同? - Patrick
@Patrick:与其在评论中回答这个问题,我会将它附加到我的答案中。我认为这对问题而言是足够相关的。 - Ken Wayne VanderLinde
有趣。所以当我执行 if (nullptr == dynamic_cast<foo*>(p)) 时,nullptr 首先被转换为 foo* 的空值,然后进行比较? - Patrick
1
理论上,指针的空值可能不是内存中清零的位。但是,当整数值 0nullptr 转换为指针类型时,必须与指针类型的空值相等。如果在 bool 上下文中评估指针,则指针类型的空值必须评估为 false,非空值则为 true。然而,大多数环境将空指针存储为一堆零位。 :) - Yakk - Adam Nevraumont

5

在布尔上下文中评估结果:

Base * p = get();

if (Derived * q = dynamic_cast<Derived *>(p))
{
    q->derived_method();
}
else
{
    // *p isn't of type Derived
}

(这适用于任何版本的C++。)

我喜欢你的解决方案,但Ken Wayne更直接地回答了我的问题,所以我将他的答案标记为最佳答案。感谢你的回答! - Patrick
这可能是更好的形式(即使nullptr一直存在),因为它适用于比仅与nullptr相比较的类型更多的类型。它适用于任何具有空概念的类型,表示为空转换为bool,例如optional<T>。我还认为对于像std::function这样可与nullptr进行比较但实际上不是指针类型的类型,它看起来更漂亮! - Ken Wayne VanderLinde

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接