74 votes

Que fait "&" dans une déclaration C++ ?

Je suis un spécialiste du langage C et j'essaie de comprendre un code C++. J'ai la déclaration de fonction suivante :

int foo(const string &myname) {
  cout << "called foo for: " << myname << endl;
  return 0;
}

En quoi la signature de la fonction diffère-t-elle de la signature équivalente en C :

int foo(const char *myname)

Y a-t-il une différence entre utiliser string *myname vs string &myname ? Quelle est la différence entre & en C++ et * en C pour indiquer les pointeurs ?

De même :

const string &GetMethodName() { ... }

Quel est le & fait ici ? Y a-t-il un site web qui explique comment & est utilisé différemment en C et en C++ ?

63voto

czuger Points 159

Le "&" indique une référence au lieu d'un pointeur vers un objet (dans votre cas, une référence constante).

L'avantage de disposer d'une fonction telle que

foo(string const& myname) 

sur

foo(string const* myname)

est que dans le premier cas, vous avez la garantie que myname est non nul, puisque le C++ n'autorise pas les références NULL. Puisque vous passez par référence, l'objet n'est pas copié, tout comme si vous passiez un pointeur.

Votre deuxième exemple :

const string &GetMethodName() { ... }

Permet de renvoyer une référence constante à une variable membre, par exemple. Ceci est utile si vous ne souhaitez pas qu'une copie soit renvoyée, et encore une fois être garanti que la valeur renvoyée est non nulle. À titre d'exemple, le texte suivant vous permet un accès direct en lecture seule :

class A
{
  public:
  int bar() const {return someValue;}
  //Big, expensive to copy class
}

class B
{
public:
 A const& getA() { return mA;}
private:
 A mA;
}
void someFunction()
{
 B b = B();
 //Access A, ability to call const functions on A
 //No need to check for null, since reference is guaranteed to be valid.
 int value = b.getA().bar(); 
}

Il faut bien sûr faire attention à ne pas renvoyer des références invalides. Les compilateurs compileront volontiers ce qui suit (en fonction de votre niveau d'avertissement et de la façon dont vous traitez les avertissements)

int const& foo() 
{
 int a;

 //This is very bad, returning reference to something on the stack. This will
 //crash at runtime.
 return a; 
}

En fait, il est de votre responsabilité de vous assurer que ce à quoi vous renvoyez une référence est réellement valide.

24voto

Victor Nicollet Points 16924

Ici, & n'est pas utilisé comme opérateur. Dans le cadre de déclarations de fonctions ou de variables, & indique une référence. La FAQ Lite de C++ dispose d'un outil très pratique, le chapitre sur références .

13voto

sohum Points 1046

Les chaînes de caractères * et les chaînes de caractères& diffèrent à plusieurs égards. Tout d'abord, le pointeur pointe vers l'adresse de la donnée. La référence pointe vers les données. Si vous aviez la fonction suivante :

int foo(string *param1);

Vous devriez vérifier dans la déclaration de la fonction que param1 pointe vers un emplacement valide. Comparativement :

int foo(string &param1);

Ici, il incombe à l'appelant de s'assurer que les données pointées sont valides. Vous ne pouvez pas passer une valeur "NULL", par exemple, dans la deuxième fonction ci-dessus.

En ce qui concerne votre deuxième question, à savoir que les valeurs de retour des méthodes constituent une référence, considérez les trois fonctions suivantes :

string &foo();
string *foo();
string foo();

Dans le premier cas, vous renverriez une référence aux données. Si votre déclaration de fonction ressemble à ceci :

string &foo()
{
    string localString = "Hello!";
    return localString;
}

Vous obtiendrez probablement des erreurs de compilation, puisque vous retournez une référence à une chaîne de caractères qui a été initialisée dans la pile pour cette fonction. Au retour de la fonction, cet emplacement de données n'est plus valide. Typiquement, vous voudriez retourner une référence à un membre de classe ou quelque chose comme ça.

La deuxième fonction ci-dessus renvoie un pointeur dans la mémoire actuelle, qui reste donc inchangé. Vous devrez cependant vérifier les pointeurs NULL.

Enfin, dans le troisième cas, les données renvoyées sont copiées dans la valeur de retour pour l'appelant. Donc si votre fonction était comme ceci :

string foo()
{
    string localString = "Hello!";
    return localString;
}

Tout irait bien, puisque la chaîne "Hello" serait copiée dans la valeur de retour de cette fonction, accessible dans l'espace mémoire de l'appelant.

8voto

gavinb Points 9237

Votre fonction déclare une constante référence à une chaîne de caractères :

int foo(const string &myname) {
  cout << "called foo for: " << myname << endl;
  return 0;
}

Une référence possède certaines propriétés spéciales qui en font une alternative plus sûre aux pointeurs à bien des égards :

  • il ne peut jamais être NULL
  • il doit toujours être initialisé
  • il ne peut pas être modifié pour se référer à une autre variable une fois qu'il a été défini
  • il peut être utilisé exactement de la même manière que la variable à laquelle il se réfère (ce qui signifie que vous n'avez pas besoin de le déférencer comme un pointeur)

En quoi la signature de la fonction diffère-t-elle de la signature équivalente en C :

int foo(const char *myname)

Il y a plusieurs différences, puisque la première se réfère directement à un objet, tandis que la seconde se réfère à un autre objet. const char* doit être déréférencé pour pointer vers les données.

Y a-t-il une différence entre l'utilisation de la chaîne *myname et de la chaîne &myname ?

La principale différence lorsqu'il s'agit de paramètres est que vous n'avez pas besoin de déréférencer &myname . Un exemple plus simple est :

int add_ptr(int *x, int* y)
{
    return *x + *y;
}
int add_ref(int &x, int &y)
{
    return x + y;
}

qui font exactement la même chose. La seule différence dans ce cas est que vous n'avez pas besoin de déréférencer x y y car ils font directement référence aux variables passées.

const string &GetMethodName() { ... }

Que fait le & ici ? Existe-t-il un site Web qui explique comment & est utilisé différemment en C et en C++ ?

Cela renvoie une référence constante à une chaîne de caractères. L'appelant peut donc accéder directement à la variable retournée, mais seulement en lecture seule. Cette méthode est parfois utilisée pour renvoyer des membres de données de chaînes de caractères sans allouer de mémoire supplémentaire.

Il y a quelques subtilités avec les références - jetez un coup d'œil à la page FAQ C++ sur les références pour plus de détails.

2voto

Chinmay Kanchi Points 16353
#include<iostream>
using namespace std;
int add(int &number);

int main ()
{
            int number;
            int result;
            number=5;
            cout << "The value of the variable number before calling the function : " << number << endl;
            result=add(&number);
            cout << "The value of the variable number after the function is returned : " << number << endl;
            cout << "The value of result : " << result << endl;
            return(0);
}

int add(int &p)
{
            *p=*p+100;
            return(*p);
}

Ce code est invalide à plusieurs égards. L'exécuter avec g++ donne :

crap.cpp: In function ‘int main()’:
crap.cpp:11: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int*’
crap.cpp:3: error: in passing argument 1 of ‘int add(int&)’
crap.cpp: In function ‘int add(int&)’:
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:20: error: invalid type argument of ‘unary *’

Une version valide du code se lit comme suit :

#include<iostream>
using namespace std;
int add(int &number);

int main ()
{
            int number;
            int result;
            number=5;
            cout << "The value of the variable number before calling the function : " << number << endl;
            result=add(number);
            cout << "The value of the variable number after the function is returned : " << number << endl;
            cout << "The value of result : " << result << endl;
            return(0);
}

int add(int &p)
{
            p=p+100;
            return p;
}

Ce qui se passe ici, c'est que vous passez une variable "telle quelle" à votre fonction. C'est à peu près équivalent à :

int add(int *p)
{
      *p=*p+100;
      return *p;
}

Cependant, le passage d'une référence à une fonction garantit que vous ne pouvez pas faire des choses comme de l'arithmétique de pointeur avec la référence. Par exemple :

int add(int &p)
{
            *p=*p+100;
            return p;
}

est invalide.

Si vous doit utiliser un pointeur vers une référence, cela doit être fait explicitement :

int add(int &p)
{
                    int* i = &p;
            i=i+100L;
            return *i;
}

Ce qui, lors d'un test, donne (comme prévu) des résultats inutiles :

The value of the variable number before calling the function : 5
The value of the variable number after the function is returned : 5
The value of result : 1399090792

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X