2009-05-29 15 views
16

Je suis un débutant C++, donc désolé si la question est trop basique.C++ vide Constructeur de chaîne

J'ai essayé de collecter la chaîne constrcturs et de les essayer tous (pour m'en souvenir).

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; 

Tous les travaux à l'exception du strA. Il imprime "1". Pourquoi? Quel est le type de la strA dans ce cas? Comment puis-je vérifier le type de choses quand je suis incertain?

J'ai remarqué que la bonne façon est-ce (qui, par la voie semble être incompatible avec les autres constructeurs, parens parfois parfois pas parens):

string strA; 

ps: question en gras, d'habitude hors de propos les réponses seront downvoted.

Répondre

32

Ceci est un gotcha très populaire. La grammaire C++ est ambiguë. L'une des règles pour résoudre les ambiguïtés est "si quelque chose ressemble à une déclaration, c'est une déclaration". Dans ce cas, au lieu de définir une variable, vous avez déclaré un prototype de fonction.

string strA(); 

est équivalent à

string strA(void); 

un prototype d'une fonction non-arg qui renvoie la chaîne.

Si vous souhaitez appeler explicitement constructeur sans arg essayez ceci:

string strA=string(); 

Il est pas entièrement équivalent - cela signifie « créer une chaîne temporaire à l'aide sans arg constructeur, puis copiez-le à initialiser la variable strA ', mais le compilateur est autorisé à l'optimiser et à omettre la copie.

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

+3

Et c'est une des raisons pour lesquelles j'ai arrêté d'utiliser C++. –

+3

@Dietrich Epp: Cela m'a dérangé aussi. Je suppose que c'est le prix payé pour garder la compatibilité C. L'alternative étant d'utiliser C, qui a sa tonne de problèmes, je pense qu'il vaut mieux garder C++ et éviter ce piège. – paercebal

+0

que diriez-vous de 'std :: string strA (" ");' – CaptainDaVinci

13

Il considère

string strA(); 

comme une déclaration de fonction.

Pour une utilisation du constructeur par défaut:

string strA; 
+2

Vous pouvez utiliser cette notation lors de l'allocation du tas: string * strA = new string(); – Skilldrick

6

En C++, comme en C, il existe une règle qui dit que tout ce qui ressemble à une declarartion sera traitée comme une déclaration.

string strA(); 

ressemble à une déclaration de fonction, donc il est traité comme un. Vous avez besoin:

string strA; 
1

compilateur interprète string strA() comme un prototype de fonction d'une fonction qui prend des arguments vides et renvoie un objet de type chaîne. Si vous voulez créer un objet chaîne vide, utilisez string strA; (sans paranthesis)

3

Il imprime 1 parce que des pointeurs vers les fonctions sont toujours converties en numérique comme true.

+5

Seulement si le pointeur vers la fonction est non nul. Quoi qu'il en soit, un pointeur sur la fonction devrait pointer vers sa définition, et cela manque ici. Cela n'aurait pas dû être lié. – MSalters

2

tkopec a raison de comprendre pourquoi cela ne fonctionne pas. Pour répondre à votre deuxième question, voici comment vérifier le type:

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

En appelant Error_(StrA); vous obtiendrez une erreur de compilation, et votre compilateur va probablement vous dire qu'il est arrivé en Error_< std::basic_string<char, std::allocator<char> > (*)(void)>(std::basic_string<char, std::allocator<char> > (*)(void)) Maintenant, std :: basic_string> est juste std :: string, donc cela signifie vraiment Error_< std::string (*)(void)> (std::string (*)(void)). La partie entre '<>' est répétée entre '()', et c'est le type de strA. Dans ce cas, std::string (*)(void).

+0

Le type de strA est une fonction. std :: string (void). Ce n'est pas un pointeur de fonction. Il devrait le déclarer comme une chaîne (* strA)(); s'il voulait que ce soit un pointeur de fonction.Je sais probablement ce que vous vouliez dire, mais vos dernières phrases sonnent comme si vous disiez que c'est un pointeur de fonction. –

4

Je ne pense pas que dans ce cas, la règle "s'il peut s'agir d'une déclaration, il s'agit d'une déclaration" s'applique. Etant donné que dans ce qui suit, les deux choses sont des déclarations

string a; 
string a(); 

L'une est la déclaration d'un objet, et l'autre est la déclaration d'une fonction. La règle s'applique dans d'autres cas. Par exemple, dans ce cas:

string a(string()); 

Dans ce cas, string() peut signifier deux choses.

  • Déclaration d'un paramètre de fonction sans nom
  • Expression création d'un défaut construit string

Le Fule applique ici et string(), on entend la même chose que ce qui suit, les paramètres nommés (noms ne sont pas pertinents dans les paramètres lors de la déclaration d'une fonction)

string a(string im_not_relevant()); 

Si une fonction prend en paramètre un tableau ou un champ sa fonction, ce paramètre se décompose en un pointeur. Dans le cas d'un paramètre de fonction, à un pointeur sur la fonction. Ainsi, il est équivalent à ce qui suit, ce qui peut paraître plus familier

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

Mais dans votre cas, il est plutôt la syntaxe qui est d'entrer dans le chemin. Il est dit que ce qui suit est une déclaration de fonction. Il ne peut jamais être la déclaration d'un objet (même si ce a probablement été conçu par le programmeur!)

string a(); 

donc il n'y a pas d'ambiguïté dans ce contexte, en premier lieu, et donc il déclare une fonction. Puisque string a un constructeur défini par l'utilisateur, vous pouvez simplement omettre les parenthèses, et l'effet reste le même que ce qui était prévu.

Questions connexes