Warum diese Return Werte?
-
Hallo ich habe folgende Frage an Euch
Warum muss ich bei folgender Methode die 0 return?
string CEvent::getTypeAsString(eTypes type) { switch ( type ) { case NOTYPE: return "NOTYPE"; break; } return 0; }
In dem Case wird ja zum Beispiel etwas returned. Aber warum mich eine 0 return?
Und außerdem 0? Der Returntyp ist doch ein String?Wenn ich das return 0 weg mache sagt der Kompiler folgendes: ( verstehe ich nicht xD )
Description Resource Path Location Type no return statement in function returning non-void [-Werror=return-type]
-
Vermutlich soll mit dem "return 0;" eben genau die Compilerwarnung umgangen werden, die du erwähnst.
Dass es in deinem Fall möglich ist, bei einem Returntype "string" eine 0 zurückzugeben, liegt am Konzept des Converting Constructors.
Du kannst das ganz einfach mit einer eigenen Klasse nachvollziehen. Und zwar nehmen wir einfach mal diesen Code:
#include <iostream> #include <string> using namespace std; class foo { public: foo(const char *bar) { cout << "foo(const char *bar) constructor called"; } }; foo foobar() { return 0; } int main() { foo f = foobar(); return 0; }
"Obwohl" die Funktion "foobar" den Rückgabetyp "foo" hat, ist es möglich, 0 zurückzugeben. Das liegt daran, dass der Compiler durch das Konzept des Converting Constructors schaut, ob es einen Konstruktor gibt, der zum Datentyp passt, den wir hier zurückgeben. Er findet dann den Konstruktor mit dem const char *, auf den die 0 passt (0 kann dazu verwendet werden, um Pointern zugewiesen zu werden. Bei anderen Zahlen geht das nicht ohne Cast. Siehe auch hier) und konstruiert ein Objekt der Klasse "foo", das er dann liefert. Du kannst das gut sehen, indem du den Code kompilierst. Es wird dann "foo(const char *bar) constructor called" ausgegeben. Um zu verhindern, dass eine solche implizite Konstruktion stattfindet, kannst du das Keyword "explicit" verwenden. Ändere dazu die Klasse foo so ab (einzige Änderung: "explicit"-Keyword in Zeile 4):
class foo { public: explicit foo(const char *bar) { cout << "foo(const char *bar) constructor called"; } };
Der Compiler wird dich dann nicht kompilieren lassen und stattdessen folgende Meldung ausspucken:
Compiler schrieb:
Error C2440 'return': cannot convert from 'int' to 'foo'
Um zu deinem Beispiel zurückzukommen: Die String-Klasse hat einen Konstruktor (der vierte), der einen const char * annimmt. Dieser Konstruktor wird bei deinem "return 0;" implizit aufgerufen. Bei mir stürzt das Programm ab, wenn ich deinen Code ausführe oder auch einfach nur einen Aufruf wie "string s(0);" im Code habe.
Das scheint also nicht gerade die feine englische Art zu sein, einen String zu initialisieren.
-
Vielen vielen Dank für deine ausführliche Antwort
-
buu2188 schrieb:
Warum muss ich bei folgender Methode die 0 return?
Solche Fragen rauben mir immer alle Energie zu antworten.
Du musst da kein return 0 stehen haben. Das ist offensichtlich eine Schlussfolgerung, die du selbst getroffen hast - warum das so ist, können wir auch nicht sagen, wir können ja nicht in deinen Kopf schauen.Also:
1. return 0 muss da nicht stehen.
2. return 0 ist sogar falsch.
3. Die Tatsache, dass der Compiler return 0 annehmen wird, ist eine etwas unglückliche Lücke in der Spezifikation; in jedem Fall ist das Verhalten deines Programmes undefiniert, falls dieses return jemals ausgeführt wird.
4. Der Compiler sagt nur, dass er irgendein (passendes) return-Statement haben will, nicht das return 0 das einzig Mögliche wäre.
5. Der Compiler beschwert sich, weil er erkannt hat, dass wenigstens ein Eingangswert existiert, für den das return im switch-Statement nicht erreicht wird. Es ist ja (abstrakt) nicht der Fall (case), dass jeder Wert für type gleich NOTYPE ist.
6. Theoretisch könnte es sein, dass dein Programm die Funktion stets nur mit NOTYPE aufruft, in diesem Fall wäre ein fehlendes return am Ende unbeachtlich. Weil der Compiler in der Regel nicht erkennen kann, ob diese Bedingung erfüllt ist oder nicht, ist dieser Hinweis des Compilers für gewöhnlich nur eine Warnung - die Hochstufung auf Fehler hast du selbst durch entsprehende Compileroptionen vorgenommen.