2013-05-16 12 views
5

Ich möchte das Ergebnis von dynamic_cast überprüfen. In C++ 11 (oder C++ 0x, für Compiler, die nullptr unterstützen), sollte ich mit nullptr oder 0 vergleichen?Liefert in C++ 11 dynamic_cast nullptr oder 0?

Ist es wichtig, und wenn ja, warum?

Ist das Ergebnis compilerabhängig?

Antwort

10

Sowohl die Konstante nullptr und die Konstante 0 (die vom Typ nullptr_t ist) werden implizit In den Nullwert eines beliebigen Zeigertyps konvertieren. Der Vergleich mit beiden wird funktionieren und ist technisch in Ordnung. Übrigens bedeutet dies, dass dynamic_cast weder eins zurückgibt noch den Nullwert für den bestimmten Zeigertyp zurückgibt.

Es ist wahrscheinlich am besten, sich angewöhnen, nullptr statt 0 zu verwenden. Soweit ich weiß, ist es nur wirklich notwendig für die richtige Überladung Auflösung (z. B. eine Überladung dauert int und eine andere dauert char*). Aus Konsistenzgründen ist es am besten, 0 zu vermeiden.

Was meine ich mit "der Nullwert eines Zeigertyps"?

Betrachten Sie eine Variable char * ptr. Es ist Typ (nicht überraschend) char *. Aber der Typ nullptr ist der spezielle Typ nullptr_t. Also, wenn wir so etwas wie ptr = nullptr schreiben, müssen einige technische Dinge passieren

  1. nullptr muss implizit in char * umgewandelt werden. Das Ergebnis dieser Konvertierung wird als neuer Wert ptr festgelegt.

Der Nullwert für char * ist das Ergebnis der nullptr zu char * umwandelt. Konzeptionell ist es immer noch nullptr, aber mit einem anderen Typ (char *). Dieser Nullwert unterscheidet sich von dem Nullwert von int * oder string * oder einem anderen Zeigertyp. Wir neigen dazu, diese Nullwerte als nur nullptr (oder 0) zu denken, aber jeder ist wirklich ein unterschiedlicher Wert von einem anderen Typ. (Die gleiche Konvertierung erfolgt übrigens zum Vergleich mit ==).

Obwohl dies wie Erbsenzählerei Details klingen mag, ist es sehr wichtig, in der Überladungsauflösung:

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

oder wenn nicht verwandt Nullwerte zuweisen:

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

Können Sie definieren, was Sie mit dem Nullwert eines Zeigertyps meinen? Wie unterscheidet sich das von 0 oder nullptr? – Patrick

+0

@Patrick: Anstatt dies in einem Kommentar zu beantworten, füge ich es meiner Antwort bei. Ich denke, es ist relevant genug für die Frage. –

+0

Interessant. Wenn ich also 'if (nullptr == dynamic_cast (p))' mache, wird 'nullptr' zuerst in den Nullwert von' foo * 'umgewandelt, und dann wird der Vergleich gemacht? – Patrick

5

das Ergebnis in einem Booleschen Kontext bewerten:

Base * p = get(); 

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

(. Dies funktioniert in jeder Version von C++)

+0

Ich mag Ihre Lösung, aber Ken Wayne mehr direkt beantwortet meine Frage, also markiere ich seine als Antwort. Danke für deine Antwort! – Patrick

+0

Dies ist wahrscheinlich die bessere Form zu verwenden (auch wenn 'nullptr' immer existiert), da es für mehr als nur Typen funktioniert, die mit 'nullptr' vergleichen.Es funktioniert für jeden Typ, der eine Leerheit hat, ausgedrückt als eine Umwandlung in 'bool', wie' optional '. Ich denke auch, es sieht besser aus für Typen wie 'std :: function', die mit' nullptr' vergleichbar sind, aber eigentlich keine Zeigertypen sind! –