Programmation C++/Les références
Présentation des références
[modifier | modifier le wikicode]Une référence peut être vue comme un alias d'une variable. C'est-à-dire qu'utiliser la variable, ou une référence à cette variable est équivalent. Ce qui signifie que l'on peut modifier le contenu de la variable en utilisant une référence.
Une référence ne peut être initialisée qu'une seule fois : à la déclaration. Toute autre affectation modifie en fait la variable référencée. Une référence ne peut donc référencer qu'une seule variable tout au long de sa durée de vie.
Déclaration
[modifier | modifier le wikicode]La déclaration d'une variable de type référence doit inclure son initialisation :
type& identificateur=variable; // Syntaxe d'initialisation des variables
// ou (strictement équivalent)
type& identificateur(variable); // Syntaxe d'initialisation des objets
Un paramètre de méthode ou de fonction de type référence est initialisé lors de l'appel à celle-ci :
type_retour nomFonctionOuMethode(type& identificateur)
{
// ...
}
// ...
nomFonctionOuMethode(variable);
Sémantique
[modifier | modifier le wikicode]La variable identificateur
est une référence vers la variable variable
. La variable variable
doit être de type type
.
Exemple de programme
[modifier | modifier le wikicode]#include <iostream>
using namespace std;
int main()
{
int a = 98,
b = 78,
c;
int &x = a;
c = x + 5; // équivaut à : c = a + 5;
int &y = b;
y = a + 10; // équivaut à : b = a + 10;
cout << "La variable b vaut : " << b << endl;
cout << "La variable c vaut : " << c << endl;
return 0;
}
Exécution
[modifier | modifier le wikicode]La variable b vaut : 108 La variable c vaut : 103
Explications
[modifier | modifier le wikicode]- Dans ce programme, on définit 3 variables entières
a
,b
etc
et on initialisea
à98
etb
à78
. int &x=a;
permet de déclarer une référencex
vers la variablea
.x+5
vaut donc la même chose quea+5
donc103
.c=x+5;
permet donc de transférer103
dans la variablec
.int &y=b;
permet de déclarer une référencey
vers la variableb
.a+10
vaut98+10
donc108
.y=a+10;
permet de transférer108
dans la variableb
.- on affiche ensuite
b
etc
c'est-à-dire respectivement108
et103
.
Pourquoi utiliser une référence ?
[modifier | modifier le wikicode]C'est la question qui peut se poser en regardant l'exemple ci-dessous, où il serait plus clair d'utiliser directement des variables.
Les références sont principalement utilisées pour passer des paramètres aux fonctions. Voir le chapitre sur les fonctions, section « passage de paramètres par référence ».
Les références constantes sont également utilisées pour référencer des résultats de retour de fonctions afin d'éviter les copies. C'est particulièrement indiqué dans le cas d'objets retournés par des fonctions. Dans ce cas, la valeur ou objet temporaire retourné a une durée de vie aussi longue que la référence.
Exemple :
class Retour
{
public:
void g() const {}
};
Retour f() { return Retour(); }
int main(int argc, char *argv[])
{
const Retour &retour = f();
retour.g();
return 0;
}
Les références et leur lien avec les pointeurs
[modifier | modifier le wikicode]Une référence est un pointeur que l'on ne peut pas réaffecter (car le compilateur l'interdit), qui se déréférence automatiquement (à l'inverse d'un pointeur pour lequel on doit utiliser l'opérateur d'indirection), et dont à l'inverse d'un pointeur on ne peut connaître l'adresse car le compilateur ne le permet pas. En effet, si v est une référence alors &v donnera l'adresse de l'objet référencé par v, et non l'adresse de la case mémoire où est stockée la référence.
Exercices
[modifier | modifier le wikicode]Exercice 1
[modifier | modifier le wikicode]Faites une fonction dont la déclaration sera void échanger(int & a, int & b)
qui devra échanger les deux valeurs.
void échanger(int & a, int & b)
{
int c = a;
a = b;
b = c;
}
Exercice 2
[modifier | modifier le wikicode]Faites une fonction pour calculer la factorielle d'un nombre. Sa déclaration sera int fact(int & n)
. La fonction sera récursive et la valeur de retour sera n. En cas de problèmes, consulter l'Aide 1.
La factorielle (notée "!") est une fonction mathématique.
Voici quelques exemple :
4! = 4 x 3 x 2 x 1 = 24
3! = 3 x 2 x 1 = 6
2! = 2 x 1 = 2
1! = 1
Notez que :
4! = 4 x 3!
3! = 3 x 2!
2! = 2 x 1! = 2 x 1
D'où :
!n = n x !(n-1) si n > 1
Voici un exemple de fonction récursive qui ne répond pas à la consigne d'avoir une déclaration int factorielle (int & n) et qui par conséquent ne peut être qualifiée de solution à l'exercice 2 :
#include <iostream>
using namespace std;
int factorielle(int n)
{
if(n == 1) return 1;
return n * factorielle(n-1);
}
int main(void)
{
int y = factorielle(2);
cout << "résultat : " << y << endl;
}
Une autre solution est (mais la fonction retourne factoriel n, pas n) :
#include <iostream>
using namespace std;
int factorielle(int& n)
{
if(n == 1) return 1;
n--;
return (n+1) * factorielle(n);
}
int main(void)
{
int n = 2;
int y = factorielle(n);
cout << "résultat : " << y << endl;
}
Une autre solution :
#include <iostream>
int fact(int & n)
{
if (n == 0)
{
n = 1;
return 0;
}
else if (n == 1) return 1;
else
{
int t = n-1;
int retVal = fact(t);
n = t * n;
return n/t;
}
}
main()
{
int v = 4;
int res = fact(v);
std::cout << res << " et sa factorielle :" << v << std::endl;
}
Tests
[modifier | modifier le wikicode]Test 1
[modifier | modifier le wikicode]Indiquez si la syntaxe est correcte ou non.
Cas 1
[modifier | modifier le wikicode]int b = n;
int & ref = b;
Cas 2
[modifier | modifier le wikicode]int x = 5;
int & var = x;
Cas 3
[modifier | modifier le wikicode]int n = 2;
int & ref = n;
if (*(ref) == 2) ref++; //ceci provoque une erreur car ref n'est pas un pointeur
Cas 4
[modifier | modifier le wikicode]#include <iostream>
using namespace std;
void afficher_par_reference(int & a)
{
cout << a << endl;
}
Cas 5
[modifier | modifier le wikicode]int b = 2;
int ref& = b;
Solution
[modifier | modifier le wikicode]- vrai
- vrai
- faux
- vrai
- faux
Test 2
[modifier | modifier le wikicode]Dans ces exemples, trouvez ce que le programme va afficher.
Cas 1
[modifier | modifier le wikicode]#include <iostream>
using namespace std;
int main()
{
int b = 2;
int a = 4;
int & ref1 = b;
int & ref2 = a;
ref2 += ref1;
ref1 -= ref2;
cout << ref2 << " " << ref1 << endl;
}
6 -4