1. Introduction au C++



sommaire chapitre 1

1.9. Pointeur ou référence

1.9.1. le mot clé this

Le mot clé this représente l'adresse de la classe et est utilisé à l'intérieur d'une des méthodes de la classe.

L'expression *this représente une référence de la classe.

1.9.2. Déclaration, utilisation

Une référence est en quelque sorte un pointeur dont l'adresse est non modifiable mais qui utilise une syntaxe différente de celle du pointeur.

Note 1: on peut déclarer un pointeur sans qu'une adresse lui soit associée, par contre lorsque l'on déclare une référence une variable du type référencé doit être affecté à la référence.

Note 2: attention, l'opérateur & possède une signification particulière pour les pointeurs ou pour les références.

  1. int main() {
  2.     int x = 1;
  3.    
  4.     // ======= pointer =======
  5.     int *ptr_x = &x;
  6.     // or
  7.     // int *ptr_x;
  8.     // ptr_x = &x;  here &x means address of x
  9.    
  10.     // use the pointer syntax to manipulate
  11.     *ptr_x = *ptr_x + 1;
  12.    
  13.     // ======= reference =======
  14.     // ref_x is a reference to an existing variable
  15.     int& ref_x = x;
  16.     ref_x = ref_x + 1;
  17.    
  18.     return 0;
  19. }
  20.  

1.9.3. Utilisation avec des classes

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4.  
  5. class Person {
  6. protected:
  7.     string name;
  8.     int age;
  9. public:
  10.     Person(string n, int a) : name(n), age(a) {
  11.     }
  12.     string get_name() {
  13.         return name;
  14.     }
  15.     int get_age() {
  16.         return age;
  17.     }
  18. };
  19.  
  20. int main() {
  21.     Person john("John", 40);
  22.    
  23.     Person *ptr_p = &john;
  24.     cout << ptr_p->get_name() << " " << ptr_p->get_age() << endl;
  25.    
  26.     Person& ref_p = john;
  27.     cout << ref_p.get_name() << " " << ref_p.get_age() << endl;
  28. }
  29.  

1.9.4. Problème

Dans l'exemple suivant la fonction function_1 tente de soustraire la valeur maximum d'une classe à la valeur minimum, les instances des classes étant passées par référence. On tente donc d'échanger les références pour que la référence smallest (resp. biggest) pointe sur la valeur minimum (resp. maximum).

Cependant cela ne peut pas fonctionner car l'instruction smallest = const_cast(y); revient à écrire x=y ou en d'autres termes à réaliser l'affectation a1 = a2

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. /**
  5.  * Definition of class A that stores an integer
  6.  */
  7. class A {
  8. public:
  9.     // value stored
  10.     int value;
  11.    
  12.     /**
  13.      * default constructor
  14.      * initialization of value to -1
  15.      */
  16.     A() {
  17.         value = -1;
  18.     }
  19.    
  20.     /**
  21.      * constructor with value
  22.      * @param v value to store
  23.      */
  24.     A(int v) {
  25.         value = v;
  26.     }
  27.    
  28.     /**
  29.      * print class contents
  30.      */
  31.     friend ostream& operator<<(ostream& out, A& obj) {
  32.         out << obj.value;
  33.         return out;
  34.     }
  35. };
  36.  
  37. // ----------------------------------------------
  38. // function that will produce an error
  39. // we are trying to exchange values
  40. // ----------------------------------------------
  41. int function_1(const A& x, const A& y) {
  42.     // by default lets assume 'x' is the smallest value
  43.     // and 'y' the biggest
  44.     A& smallest = const_cast<A&>(x);
  45.     A& biggest = const_cast<A&>(y);
  46.    
  47.     cout << "> in function:" << endl;
  48.     cout << "smallest = " << smallest << endl;
  49.     cout << "biggest  = " << biggest << endl;
  50.    
  51.     // if it is not the case then exchance 'x' and 'y'
  52.     if (smallest.value > biggest.value) {
  53.         // !!!!! problem here !!!!!
  54.         // it is equivalent to: x = y
  55.         smallest = const_cast<A&>(y);
  56.          
  57.         biggest = const_cast<A&>(x);
  58.         cout << "> in function after exchange:" << endl;
  59.         cout << "smallest = " << smallest << endl;
  60.         cout << "biggest  = " << biggest << endl;      
  61.     }
  62.    
  63.     return (biggest.value - smallest.value);
  64. }
  65.  
  66. // ----------------------------------------------
  67. // valid function
  68. // we are trying to exchange values
  69. // ----------------------------------------------
  70. int function_2(const A& x, const A& y) {
  71.     // work on values not references
  72.     int smallest = x.value;
  73.     int biggest  = y.value;
  74.    
  75.     cout << "> in function:" << endl;
  76.     cout << "smallest = " << smallest << endl;
  77.     cout << "biggest  = " << biggest << endl;
  78.    
  79.     if (smallest > biggest) {
  80.         swap(smallest, biggest);
  81.     }
  82.    
  83.     return (biggest - smallest);
  84. }
  85.  
  86.  
  87. // ----------------------------------------------
  88. // main function
  89. // ----------------------------------------------
  90. int main() {
  91.     A a1(7), a2(5);
  92.  
  93.  
  94.     cout << "==== with function_1 ====" << endl;
  95.     cout << "initially :" << endl;
  96.     cout << "a1 = " << a1 << endl;
  97.     cout << "a2 = " << a2 << endl;
  98.    
  99.     int r = function_1(a1, a2);
  100.     cout << "r = " << r << endl;
  101.    
  102.     // !!! a1 is modified after call to function !!!
  103.     cout << "finally :" << endl;
  104.     cout << "a1 = " << a1 << " !!! should be 7" << endl;
  105.     cout << "a2 = " << a2 << endl;
  106.  
  107.     cout << "==== with function_2 ====" << endl;
  108.     A b1(7), b2(5);
  109.     cout << "initially :" << endl;
  110.     cout << "b1 = " << b1 << endl;
  111.     cout << "b2 = " << b2 << endl;
  112.    
  113.     r = function_2(b1, b2);
  114.     cout << "r = " << r << endl;
  115.    
  116.     cout << "finally :" << endl;
  117.     cout << "b1 = " << b1 << endl;
  118.     cout << "b2 = " << b2 << endl;
  119.    
  120.     return 0;
  121. }
  122.  
  123.  
  124.  

Pour pallier à ce problème il faut échanger les valeurs des classes et non leurs références comme dans function_2.