Référence et surcharge de fonction

Exemple

void f(int param) {
param = 2;
}
void g(int& param) {
param = 2;
}
int& h(int& param) {
return param;
}
int main(void) {
int a = 2;
int& b = a;
b = 3;
// ici b et a ont pour valeur 3
b=3;
// ici b et a ont pour valeur 1
a=1;
f(a);
// a est resté sur 1
f(b);
// ici a et b valent toujours 1
g(a);
// ici a vaut 2
// on ne peut pas définir une référence non initialisée
// int& c; --> ne fonctionnera pas
// int& c = 3; --> erreur aussi car 3 n'est pas une variable
/* Représentation d'une variable
* peut donc être modifiée */
h(a) = 4;
// ici a (et b) vale(nt) 4
return 0;
}

Manière de voir une référence

int main(void) {
int b = 4;
int& r = b; // int* r = &b; à l'initalisation seulement
r = expr; // *r = expr;
return 0;
}

Récapitulatif catégorie (lvalue et rvalue) et type

lvalue -> left-value
rvalue -> right-value

int main(void) {
int a, b;
// ici on assigne la valeur contenu dans b dans la variable a
a = b;
// un peu comme
a = 3; // --> possible
// 3 = a --> pas possible
return 0;
}

Toute expression possède un type (int, float, struct A { }, int*, A*) et une catégorie (lvalue et/ou rvalue).
Les références doivent être réinitialiser avec une expression lvalue.

Exemple de lvalue

int main(void) {
int T[10];
T[1]; // équivalent à *(T+1) est une lvalue
T[1] = 3; // et donc on a le droit d'écrire
int& a = T[1]; // Ok T[1] est lvalue
return 0;
}

Surcharge de fonction

En C on a pas le droit de définir deux fonctions du même nom, c’est possible en C++ lorsque ces deux fonctions ne prennent pas les mêmes arguments

Exemple

int fonction(int a) { ... } // fonction 1 (signature fonction(int _))
void fonction(float a) { ... } // fonction 2 (signature fonction(float _))
// void fonction(int c) { ... } /* erreur -> il existe déjà une */
/* fonction(int _);
* --> le type de retour n'influe donc
* pas sur la surcharge */
float fonction(int a, int b) { ... } // ok (signature fonction(int _, int _))
int main(void) {
fonction(3); // fonction 1 appellée car 3 est de type integer
fonction(3.1f); // fonction 2 appellée car 3. est de type float
return 0;
}

La signature d’une fonction est la liste de son identifiant suivie de la liste des types de paramètres.

Règles de la signature unique

Dans un même espace de nom, on peut définir plusieurs fonction ayant le même identifiant tant que leur signature sont toute différente deux à deux.

Choix de la fonction

void procedure(long int a) { ... }
void procedure(float a) { ... }
struct A { ... };
void maFonction(A a) { ... } // fonction 1
void maFonction(float c) { ... } // fonction 2
void maFonction(float c, float b) { ... } // fonction 3
int main(void) {
procedure(3); /* on sait pas trop quelle fonction va être appellée
* - soit on convertis en long int, soit en float
* -> donc erreur du compilateur à cause de l'ambiguïté */
procedure((long int)3); /* Dans ce cas là, la procédure 1
* est correctement choisie car on
* force la conversion. */
maFonction(3); /* ok fonction 2 choisie car
* aucune ambiguïté/conversion possible */
maFonction(4, 5); // idem, fonction 3 choisie et tout est ok
return 0;
}

Lors d’un appel de fonction surchargée

Valeur par défaut de paramètre fonction

void maFonction(int a, int b = 2, int c = 4) { ... }
// void procedureTruc(int a = 2, int b) { ... } /* erreur car les */
/* paramètres par défaut
* doivent être à la fin */
int main(void) {
maFonction(3); // ok | a = 3, b = 2 et c = 4
maFonction(2, 4); // ok | a = 2, b = 4 et c = 4
maFonction(6, 7, 1); // ok | a = 6, b = 7 et c = 1
// maFonction(); // erreur car a non renseignéint *p*
return 0;
}