2010-01-20 5 views
3

Je me demande pourquoi C++ (et peut-être d'autres langages, je ne suis pas sûr) ne permet pas de telles instructions.Pourquoi C++ ne met-il pas en œuvre les fonctions construction + appel sur la même ligne?

MyObject foo.DoBar(); 

Vous penseriez que le langage pourrait comprendre pour construire l'objet, puis appelez la fonction. La seule raison pour laquelle je peux penser à cela ne marche pas, c'est que si la construction de l'objet échouait, l'instruction essaierait quand même d'appeler la fonction.

Quelles sont les raisons pour lesquelles ceux qui aident à développer et intégrer de nouvelles fonctionnalités en C++ (et éventuellement d'autres langages) ne le permettent pas?

Répondre

13

Vous peut construire un objet et immédiatement appeler une fonction là-dessus, vous ne pouvez pas affecter l'objet à une variable si vous le faites:

MyObject().DoBar(); 

Une raison pratique de cette restriction est que le constructeur crée l'objet et la fonction que vous appelez pourrait également avoir une valeur de retour, de sorte que vous finiriez avec deux valeurs produites par la même instruction. Ensuite, vous aurez besoin d'une syntaxe spéciale pour affecter ces deux valeurs aux variables, ce qui ne se produit nulle part ailleurs.

Et le peu de confort que l'appel direct de la méthode peut apporter n'est pas si grand qu'il serait utile d'introduire une nouvelle syntaxe.

+0

J'aime cette syntaxe: "MyObject foo(). SetConfidential(). SetAsynchrone()", je trouve qu'il est plus facile à utiliser qu'un tas de variations de constructeurs qui ne font qu'aggraver le pauvre utilisateur. –

+0

@Matthieu: Vous pouvez chaîner des mutateurs d'état dans la ligne après la déclaration. Je ne pense pas que ce soit un vrai problème. –

+0

@David: oui, heureusement. Ou pouvez-vous utiliser une fausse assignation 'MyObject foo = MyObject(). Set();' bien que je me demande si elle est correctement optimisée. –

3

Je pense que la meilleure question est pourquoi devrait-il? Après tout:

MyObject foo; 
foo.DoBar(); 

Est à peine plus difficile. C'est plus lisible aussi (bien que cela puisse évidemment être biaisé.) Même si vous pouviez construire-appel, il serait probablement étiqueté comme une "mauvaise chose" à faire. Sorte de comment plusieurs déclarations sur la même ligne sont autorisées, mais diminuent souvent la lisibilité. Une telle construction ajoute des règles et de la complexité à un langage déjà complexe, lorsqu'une solution probablement préférable est déjà présente. Voulons-nous vraiment ajouter du sucre coûteux à une langue juste pour sauver quelques frappes?

En réponse à: «Je pouvais le voir être utile que lorsque vous voulez construire un objet et il suffit d'appeler une fonction sur elle »

Si vous voulez construire un objet juste pour appeler une fonction, serait-il possible de faire de cette fonction une fonction libre? Après tout, il fonctionne sur les données par défaut ou les données qui ont été transmises au constructeur de toute façon. La seule chose qui manque serait le destructeur.

Sans parler de l'autre option:

struct MyObject 
{ 
    MyObject(bool pCallDoBar = true) 
    { 
     if (pCallDoBar) 
      DoBar(); 
    } 

    void DoBar(void) 
    { 
    } 
}; 

MyObject foo; 

Ou tout simplement:

MyObject().DoBar(); // destructor called here, though 

Je pense que vous auriez besoin d'un exemple concret pour faire vraiment une affaire.

+0

Je pourrais le voir utile quand vous voulez construire un objet et juste appeler une fonction dessus. Cependant, je vois clairement d'où vous venez en termes de lisibilité et, dans la plupart des cas, je suis d'accord. – Anonymous

+2

Si vous construisez un objet et appelez une fonction, alors vous pouvez faire MyObject(). Foo() '. – jamesdlin

+0

@james: D'aw, vous me battez:] Le seul problème est que "perd" le destructeur, si le nom devait rester. (Pensez mutex.) – GManNickG

0

Eh bien, voici un problème: que se passe-t-il si foo doit utiliser un constructeur autre que celui par défaut? Maintenant, il est

MyObject foo(arg1, arg2).DoBar(); 

C'est un peu en désordre et est vraiment pas beaucoup mieux que

MyObject foo(arg1, arg2); 
foo.DoBar(); 

Rappelez-vous: Code devrait être facilement understandible!

Notez que, il est un peu possible de faire ce que vous voulez, si dobar renvoie une référence à *this:

MyObject foo = MyObject().DoBar(); 

Avec C++ 0x déplacer les constructeurs, cela entraînera peu de frais généraux, mais jusque-là, attendre une fausse copie.

2

Dans votre dernier paragraphe, vous faites référence au comité de normes C++. Il a été très occupé, et d'importantes fonctions linguistiques ont été supprimées parce que le comité manque de temps (par exemple std::unordered_map dans la norme actuelle et les concepts dans le prochain). Ils ne sont pas intéressés à faire des changements mineurs sans raison valable. Dans les jours précédant le comité de normalisation, Bjarne Stroustrup n'était pas intéressé à ajouter des fonctionnalités mineures juste pour les avoir. C ne possédait pas cette déclaration, peut-être parce que personne n'en voulait (peu de personnes ont déclaré des types avec des fonctions associées à l'époque), peut-être parce que cela pourrait être déroutant. Beaucoup de caractéristiques des langages informatiques sont là à des fins historiques, et peuvent indiquer que quelqu'un a fait un choix aléatoire il y a plusieurs décennies. Cela ne veut pas dire que c'est une bonne idée de les changer sans raison valable, une fois qu'ils sont établis.

La bonne question n'est pas "pourquoi ne font-ils pas ce changement?" mais "pourquoi devraient-ils faire ce changement?" Votre changement proposé ne semble pas vraiment utile, puisque je peux faire exactement la même chose avec deux lignes de code; le total de la frappe supplémentaire est un point-virgule, une fin de ligne et la répétition du nom de la variable. L'inconvénient est qu'il ajouterait une syntaxe supplémentaire au langage, et il soulève la question des valeurs de retour (comme l'a souligné sth). La valeur de retour de la fonction appelée doit-elle être supprimée? La fonction appelée doit-elle être obligée de renvoyer void ou une variante sur this? Toute solution que je peux voir en ce moment va être déroutante dans certaines circonstances, et tout ce dont C++ a besoin n'est pas plus une opportunité de se confondre.

Questions connexes