Question

class mystring {
 friend ostream& operator<<(ostream &out, const mystring ss) {
        out << ss.s;
        return out;
    }
private:
    string s;
public:
    mystring(const char ss[]) {
        cout << "constructing mystring : " << ss << endl;
        s = ss;
    }
};

void outputStringByRef(const mystring &ss) {
 cout << "outputString(const string& ) " << ss << endl;
}

void outputStringByVal(const mystring ss) {
 cout << "outputString(const string ) " << ss << endl;
}

int main(void) {
    outputStringByRef("string by reference");
    outputStringByVal("string by value");
    outputStringByRef(mystring("string by reference explict call mystring consructor"));
    outputStringByVal(mystring("string by value explict call mystring constructor"));
} ///:~

En considérant l'exemple ci-dessus, on ne pouvait pas modifier la variable passe par référence, ni pourrait-on modifier le passage par la valeur de sortie de variable.Dispositif de chacune des méthodes est same.Since il n'y a pas de différence entre ces deux procédé, pourquoi ne C ++ prennent en charge les méthodes?

merci.

Était-ce utile?

La solution

Il y a une différence entre les deux. Considérez ce qui suit:

#include <iostream>
#include <string>
using std::string;

string g_value;

void callback() {
    g_value = "blue";
}

void ProcessStringByRef(const string &s) {
    callback();
    std::cout << s << "\n";
}

void ProcessStringByValue(const string s) {
    callback();
    std::cout << s << "\n";
}

int main() {
    g_value = "red";
    ProcessStringByValue(g_value);
    g_value = "red";
    ProcessStringByRef(g_value);
}

Sortie:

red
blue

Juste parce qu'une référence est const dans une fonction, ne signifie pas que le referand ne peut pas être modifié par d'autres références (la situation d'un objet ayant de multiples références ou des pointeurs vers elle est appelée « aliasing »). Ainsi, il y a une différence entre le passage d'une référence const, et en passant une valeur const - dans le cas de la référence, l'objet peut changer après l'appel est effectué. Dans le cas de la valeur, l'a une copie callee privée, qui ne changera pas.

Comme ils font des choses différentes, C ++ vous permet de choisir vous voulez.

Il y a des conséquences pour les performances ou l'autre manière - lorsque vous passez en valeur, une copie doit être faite, qui coûte. Mais le compilateur sait alors que seule votre fonction peut éventuellement avoir des références à cette copie, ce qui pourrait permettre à d'autres optimisations. ProcessStringByRef ne peut pas charger le contenu de la chaîne pour l'impression jusqu'à ce que callback() est de retour. ProcessStringByValue peut, si le compilateur pense le faire est plus rapide.

En général, vous vous souciez de la copie, non pas l'ordre d'exécution des instructions, car en général la copie est beaucoup plus cher. Donc, en général, vous passez par référence, si possible, pour les objets qui sont à copier non trivial. Mais la possibilité d'aliasing a parfois des conséquences très graves pour la performance, en empêchant certains Optimisations même si aucun aliasing se produit réellement. Voilà pourquoi « règles strictes » d'aliasing existent, et le mot-clé restrict dans C99.

Autres conseils

f(const string&) prend chaîne par référence const: fis agissant directement sur l'objet chaîne passée par référence: il n'y a pas de copie impliqué. const empêche les modifications de l'objet original cependant.

f(const string) prend une valeur de chaîne, ce qui signifie f reçoit une copie de la chaîne d'origine. Même si vous laissez tomber const, en passant par la valeur, toute modification de la chaîne est perdue lors du retour de f.

Je ne sais pas exactement ce que vous entendez par « Pourquoi C ++ prennent en charge les méthodes? ». Il est des règles de surcharge juste générales applicables.

passe f(string s) en valeur la chaîne s, en d'autres termes, il crée une copie et initialisées avec la valeur de la chaîne que vous passez. Toute modification apportée à la copie, ne sera pas propagé à la chaîne d'origine que vous avez passé pour appeler la fonction. Dans f(const string s) const est redondant parce que vous ne pouvez pas changer de toute façon la valeur d'origine.

Dans f(const string& s) au lieu de la chaîne n'est pas copier, mais vous passez une référence. Cela se fait habituellement lorsque vous avez un grand objet de sorte que le « passage par la valeur » peut produire une surcharge (c'est pourquoi c ++ prend en charge les méthodes). Passant par référence signifie que vous pouvez modifier la valeur de la « grande » objet que vous passez, mais à cause de la spécificateur const, vous ne pouvez pas le modifier. Il est une sorte de « protection ».

votre objet pourrait contenir un mutable membre, qui peut même être modifié avec un référence const

Avec outputStringByRef vous devez vous assurer que la variable vous passez une référence à demeure vivante et inchangée aussi longtemps que les besoins outputStringByRef il. avec outputStringByVal la variable que vous avez passé peut mourir ou sortir de la portée et la copie que la fonction a est toujours ok.

Il est (presque) pas de différence en termes de pouvoir modifier la chaîne dans la fonction. Cependant, il y a une grande différence en termes de ce qui est passé. La surcharge de const mystring &ss prend une référence const à la chaîne. Bien qu'il ne puisse le modifier, il est de la même mémoire étant adressée. Si la chaîne est longue, cela peut être un facteur important (en supposant que la chaîne ne soit pas mis en œuvre en utilisant copie -on-écriture). Le formulaire de const mystring ss fait une copie de la chaîne, de la mémoire si différente sera abordée.

En fait, la forme const mystring &ss peut changer la chaîne, si un const_cast<mystring&> a été utilisé -. Bien que je ne recommanderais pas ici

Imaginez que vous voulez imprimer un objet qui ne peut être copié:

Thread th;
// ...
cout << th; // print out informations...

La version de référence ne copiera pas le fil, mais prendra l'adresse de th et de créer un alias pour elle. L'autre version essayerait de copier le fil lors du passage par valeur -. Mais la copie ne peut pas être senseful pour un tel objet (? Y aurait-il un fil supplémentaire alors)

Il peut vous aider à penser à copier un objet le clonage d'un objet . Copie th ci-dessus en C ++ ne signifie pas seulement d'avoir une autre poignée pour le même objet que dans Java - cela ne signifie cloner implicitement l'objet désigné, et avoir une copie entière de celui-ci. La question est donc similaire à « Pourquoi Java supporte à la fois Object.clone et la copie des références? » - les deux ont des fins différentes.

Et puis il y a une question de performances aussi, après tout. Vous ne voulez pas copier chaque fois que vous passez quelque chose autour des objets qui ont faim de ressources.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top