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