Références de déplacement et références constantes et recopie

const int \neq int, ils ont le même type mais un objet différent.

Il faut toujours initalisé les const.

void f(const int a) { ... }
void f(int a) { ... }

int main(void) {
    int i;
    const int ci = 4;

    int *p;
    const int* p2;

    const int* const p3 = &i; 
    int *const p4 = &i; /* on peut pas faire = &ci car on pointerais vers
                         * une const */
        // p = &ci /* pareil on ne doit pas modifier
               /* une const donc impossible de faire ça */

    return 0;
}

Utilisation dans des classes

#include<iostream>

using namespace std;

class A {
    // private: // privé par défaut donc inutile
        const int a;
        const int b;

    public:
        A(int pa, int pb = 4) : a(pa), b(pb) { } /* l'ordre est important
                                                  * c'est a, puis b, car on
                                                  * demande pa, puis pb 
                                                  * (respect de l'ordre de 
                                                  * construction) */

        voidafficher(void) {
            cout << a << endl;
            cout << b << endl;
        }
};

int main(void) {
    A objet1(3, 6);
    objet1.afficher();

    A objet2(3);
    objet2.afficher();

    return 0;
}

Références constantes

int main(void) {
    int a = 1;
    const int& r = a;
    // r = 3; // impossible, on ne peut pas modifier depuis une const
    a = 2; // possible
    const int& r = b; // possible
    // int& r2 = b; // impossible aussi pour la même raison que précedemment

    return 0;
}

Une rvalue peut être référencé à l’aide d’une référence constante.

#include<iostream>

using namespace std;

class A {
        const int a;
        const int b;

    public:
        A(int pa, int pb = 4) : a(pa), b(pb) { }

        voidafficher(void) const { // mot clé const ici !!!
            cout << a << endl;
            cout << b << endl;
        }
};

A g(void) {
    // autre syntaxe pour appeller le constructeur
    return A { 2 };
}

int main(void) {
    int a;
    int& r = a;
    const A& r1 = g();
    r1.afficher();

    // encore une autre syntaxe de constructeur
    A objet = 4; /* == objet { 4 }; --> valable que quand
                  *                     il n'y a qu'un seul
                  *                     paramètre */
    
    return 0;
}

Explication de pourquoi on a le mot clé const à la suite de la fonction

Explicit le fait que la fonction ne modifie rien à l’objet.
-> Si on utilises const à mauvais escient, le compilateur refusera de compiler.
-> Si on veut quand même modifier quelque chose dans la fonction const, il faut le faire sur un attribut mutable
-> Mot clé static permet qu’une valeure soit gardé d’un objet à l’autre quand définie dans une classe.

Exemple

#include<iostream>

using namespace std;

class Paire {
    int a;
    int b;
    mutable int temp;
    static int nb; /* ici c'est une déclaration pour
                    * pouvoir le définir à l'exterieur */

    public:
        Paire(int pa, int pb) {
            a = pa;
            b = pb;
            nb++;
        }

        void afficher(void) const {
            temp = 1;
            cout << "p: " << a << ", s: " << b << endl;
        }

        static int compter() {
            return nb;
        }

        ~Paire() {
            nb--;
        }
};

int Paire::nb = 0; // ici c'est une définition (dans un seul fichier objet)

int main(void) {
    cout << Paire::compter() << endl; // on l'appel en dehors de la classe
    Paire const a(4, 2);
    a.afficher();

    cout << Paire::compter() << endl;

    {
        Paire b(1, 1); 
        cout << Paire::compter() << endl; // on l'appel en dehors de la classe

        Paire c(1, 1);
        cout << Paire::compter() << endl; // on l'appel en dehors de la classe
    }

    cout << Paire::compter() << endl; // on l'appel en dehors de la classe

    return 0;
}

Une variable static doit être définie à l’extérieur car elle est unique, il faut donc la définir en dehors de la classe pour que “tout le monde” soit au courant que cette variable est reservée.

Constructeur de recopie tab

#include<iostream>

using namespace std;

class Tab {
    int* tab;
    // int taille; -> on se dit que tout les tableaux sont de taille 10
    
    public:
        Tab(void) {
            cout << "appel du constructeur" << endl;
            tab = new int[10];
            
            for(int i = 0; i < 10; i++)
                tab[i] = 0;
        }
    
        Tab(Tab const &original) { // ici c'est le constructeur de recopie
            cout << "appel du constructeur de copie" << endl;
            tab = new int[10];
            for(int i = 0; i < 10; i++)
                tab[i] = original.tab[i];
        }

        void set(int indice, int val) {
            tab[indice] = val;
        }

        void afficher(void) {
            for(int i = 0; i < 10; i++) {
                cout << tab[i];
                cout << " ";
            }
            cout << endl;
        }
    
        ~Tab() {
            cout << "appel du destructeur" << endl;
            delete[] tab;
        }
};

void f(Tab b) {
    b.set(3, 1);
    b.afficher();
}

int main(void) {
    Tab a;

    a.set(3, 5);
    a.afficher();

    f(a);
    a.afficher();

    return 0;
}

Le constructeur de recopie est appellée automatiquement lors d’un appel de fonction.