2009-05-29 16 views
16

Ich bin ein C++ Anfänger, also tut mir leid, wenn die Frage zu einfach ist.C++ leer String Konstruktor

Ich habe versucht, die String-Konstrukteure zu sammeln und alle auszuprobieren (um sie zu erinnern).

string strA();   // string(); empty string // incorrect 
string strB("Hello"); // string(const char* str) 
string strC("Hello",3); // string(const char* str, size_type length) 
string strD(2,'c');  // string(size_type lenght, const char &c) 
string strE(strB);  // string(const string& s) 

cout << strA << endl; 
cout << strB << endl; 
cout << strC << endl; 
cout << strD << endl; 
cout << strE << endl; 

Alle von ihnen arbeitet mit Ausnahme der strA. Es druckt "1". Warum? Was ist der Typ des strA in diesem Fall? Wie kann ich die Art des Materials überprüfen, wenn ich unsicher bin?

ich, dass der richtige Weg bemerkt haben, ist dies (die übrigens mit den anderen Konstrukteuren als unvereinbar scheint, manchmal manchmal keine Pars parens):

string strA; 

ps: Frage in fett, gewöhnlich irrelevant Antworten werden abgelehnt.

Antwort

32

Dies ist eine sehr beliebte gotcha. C++ - Grammatik ist mehrdeutig. Eine der Regeln zum Auflösen von Mehrdeutigkeiten lautet: "Wenn etwas wie eine Deklaration aussieht, ist es eine Deklaration". In diesem Fall haben Sie, anstatt eine Variable zu definieren, einen Funktionsprototyp deklariert.

string strA(); 

entspricht

string strA(void); 

ein Prototyp eines no-Arg-Funktion, die Zeichenkette zurückgibt.

Wenn Sie wünschen ausdrücklich keine argument Konstruktor aufzurufen versuchen, diese:

string strA=string(); 

Es ist nicht völlig gleichwertig ist - es bedeutet ‚erstellen Sie eine temporäre Zeichenfolge keinen argument Konstruktor und dann kopieren Sie es Variable initialisieren strA ', aber der Compiler darf ihn optimieren und das Kopieren weglassen.

EDIT: Here is an appropriate item in C++ FAQ Lite

+3

Und das ist ein Grund, warum ich aufgehört habe C++ zu benutzen. –

+3

@Dietrich Epp: Das hat mich auch gestört. Ich denke, das ist der Preis, der gezahlt wird, um die Kompatibilität mit C zu wahren. Die Alternative, C zu verwenden, die ihre metrische Tonne von Problemen hat, ist meine Vermutung, dass es besser ist, C++ zu behalten und diesen Fallstrick zu vermeiden. – paercebal

+0

Wie wäre es mit 'std :: string strA (" ");' – CaptainDaVinci

13

Er hält

string strA(); 

als Funktionsdeklaration.

Für Standardkonstruktors Verwendung:

string strA; 
+2

Sie können diese Notation verwenden, wenn Sie den Heapspeicher nicht zuordnen: string * strA = new string(); – Skilldrick

6

In C++, wie in C, gibt es eine Regel, die besagt, dass alles, was wie ein declarartion aussieht wird als Erklärung behandelt werden.

string strA(); 

sieht wie eine Funktionsdeklaration aus, so wird es als eins behandelt. Sie benötigen:

string strA; 
1

Compiler interpretiert string strA() als Funktion Prototyp einer Funktion, die Leere Argumente nimmt und gibt ein Objekt vom Typ string. Wenn Sie ein leeres String-Objekt erstellen möchten, verwenden Sie string strA; (ohne Paranthesis)

3

Er druckt 1 weil Zeiger auf Funktionen immer auf numerische umgewandelt werden als true.

+5

Nur wenn der Zeiger auf die Funktion nicht null ist. Wie auch immer, ein Zeiger auf Funktion sollte auf seine Definition zeigen, und das fehlt hier. Dies hätte nicht verlinken sollen. – MSalters

2

tkopec ist richtig, warum es nicht funktioniert. Um Ihre zweite Frage zu beantworten, ist hier, wie Sie den Typ überprüfen:

template<typename TEST> void Error_() { 
    TEST* MakeError = 1; 
} 

von Error_(StrA); ruft Sie einen Compiler-Fehler erhalten wird, und der Compiler wird wahrscheinlich sagen, dass es in Error_< std::basic_string<char, std::allocator<char> > (*)(void)>(std::basic_string<char, std::allocator<char> > (*)(void)) Nun geschah, std :: basic_string> ist nur std :: string, also das bedeutet wirklich Error_< std::string (*)(void)> (std::string (*)(void)). Der Teil zwischen '<>' wird zwischen '()' wiederholt, und das ist der Typ von strA. In diesem Fall std::string (*)(void).

+0

Art von StrA ist eine Funktion. Std :: Zeichenfolge (void). Es ist kein Funktionszeiger. Er müsste es als String deklarieren (* strA)(); wenn er wollte, dass es ein Funktionszeiger ist.Ich weiß wahrscheinlich, was du meintest, aber deine letzten Sätze klingen wie du sagst, es ist ein Funktionszeiger. –

4

Ich glaube nicht, dass in diesem Fall die Regel "wenn es eine Deklaration sein könnte, es ist eine Deklaration" gilt. Da im Folgenden beide Dinge sind Erklärungen

string a; 
string a(); 

Die eine der Erklärung eines Objekts ist, und die andere ist die Erklärung einer Funktion. Die Regel gilt in anderen Fällen. Zum Beispiel, in diesem Fall:

string a(string()); 

In diesem Fall kann string() zweierlei bedeuten.

  • Erklärung eines ungenannten Funktionsparameter
  • Expression eines Standard Erstellen konstruiert string

Die fule hier gilt, und string() ist die gleiche wie die folgenden zu verstehen, mit dem Namen Parameter (Namen sind irrelevant in Parametern beim Deklarieren einer Funktion)

string a(string im_not_relevant()); 

Wenn eine Funktion als Parameter ein Array oder einen anderen Parameter verwendet ihre Funktion zerfällt dieser Parameter in einen Zeiger. Im Falle eines Funktionsparameters einen Zeiger auf die Funktion. Somit ist es dem folgenden äquivalent, die mehr aussehen vertraut

string a(string (*im_not_relevant)()); 

Aber in Ihrem Fall, es ist vielmehr die Syntax, die in der Art und Weise wird immer. Es sagt, dass das folgende eine Funktionsdeklaration ist. Es kann nie die Deklaration eines Objektes sein (auch wenn das wahrscheinlich durch den Programmierer gedacht war!)

string a(); 

So gibt es keine Zweideutigkeit in diesem Zusammenhang in erster Linie, und so erklärt es eine Funktion. Da string einen benutzerdefinierten Konstruktor hat, können Sie einfach die Klammern weglassen, und der Effekt bleibt derselbe wie beabsichtigt.