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
- S’il existe une fonction dont les types des paramètres correspondent exactement aux arguments de la fonction alors cette fonction est forcément unique (règle de la signature unique) et elle est donc choisie par le compilateur.
- Sinon le compilateur essaye de choisir une fonction en effectuant des conversions implicites des arguments.
- Si le compilateur trouve plusieurs fonction candidates ou aucune, une erreur survient.
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; }