I want to check the result of dynamic_cast. In c++11 (or c++0x, for compilers that support nullptr), should I compare against nullptr or 0?
Does it matter, and if so, why?
Is the result compiler-dependent?
The primary purpose for the dynamic_cast operator is to perform type-safe downcasts. A downcast is the conversion of a pointer or reference to a class A to a pointer or reference to a class B , where class A is a base class of B .
If the cast is successful, dynamic_cast returns a value of type new-type. If the cast fails and new-type is a pointer type, it returns a null pointer of that type. If the cast fails and new-type is a reference type, it throws an exception that matches a handler of type std::bad_cast.
If it is, dynamic_cast<Type*> returns a pointer; otherwise it returns NULL.
dynamic_cast: This cast is used for handling polymorphism. You only need to use it when you're casting to a derived class. This is exclusively to be used in inheritance when you cast from base class to derived class.
Both the constant nullptr
(which is of type nullptr_t
) and the constant 0
will implicitly convert to the null value of any pointer type. So comparing against either one will work and is technically OK. By the way, this means that dynamic_cast
return neither one, it returns the null value for the particular pointer type.
It's probably best to get in the habit of using nullptr
rather than 0
. As far as I know, it's only really necessary for proper overload resolution (e.g. one overload takes int
and another takes char*
). For consistency, avoiding 0
will be best.
What do I mean by "the null value of a pointer type"?
Consider a variable char * ptr
. It's type is (unsurprisingly) char *
. But the type of nullptr
is the special type nullptr_t
. So when we write something like ptr = nullptr
, some technical things must happen
nullptr
must be implicitly converted to char *
.ptr
.The null value for char *
is the result of converting nullptr
to char *
. Conceptually, it's still nullptr
, but with a different type (char *
). This null value is distinct from the null value of int *
or string *
or any other pointer type. We tend to think of these null values as just nullptr
(or 0
), but each one is really a distinct value from a different type. (By the way, the same conversion happens for comparison using ==
).
Although this may sound like nitpicking details, it's very important in overload resolution:
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*
}
or when assigning unrelated null values:
char * c_ptr = nullptr; // Okay
int * i_ptr1 = nullptr; // Okay
int * i_ptr2 = c_ptr; // COMPILER ERROR HERE
Evaluate the result in a boolean context:
Base * p = get();
if (Derived * q = dynamic_cast<Derived *>(p))
{
q->derived_method();
}
else
{
// *p isn't of type Derived
}
(This works in any version of C++.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With