Fonctions et classes amies, espace de nom

Fonctions et classes amies

Exemple de fonction ami

#include<iostream>

class A {
    int a;
    friend void f(void);
    friend int main(void);
};

void f(void) {
    A obj;
    obj.a = 1;
}

int main(void) {
    A obj;
    obj.a = 3;
    std::cout << obj.a << std::endl;

    return 0;
}

Une fonction amie peut modifier des attributs d’une classe. On peut aussi le faire pour les membres d’une classe

Exemple

#include<iostream>

class A {
    int a = 1;
    friend void f(void);
    friend int main(void);
    friend class B; // classe B déclarée ami de la classe A
};

class B {
    A objA;
    
    public:
        void modif(void) {
            objA.a = 5;
        }

        void affiche(void) {
            std::cout << objA.a << std::endl;
        }
};

int main(void) {
    B objB;
    objB.affiche();
    objB.modif();
    objB.affiche();

    return 0;
}

Résumé amis

On peut déclarer amie d’une classe A une fonction f externe de la classe A avec le mot clé friend. Ce qui permet à la fonction f d’acceder aux membres privés de la classe A. On peut rendre une classe B amie d’une classe A, ce qui a pour effet de rendre toute les méthode de la classe B comme des fonctions amie de la classe A.

Exemple

class A {
    friend void f(void); // f est l'amie de la classe A
    friend class B; // B est l'amie de la classe A
};

class B { ... };
void f(void) { ... };

Espace de nom

Les identificateurs servent à nommer :

Les identificateurs peuvent être créer à partir de :

Exemple de déclaration sans définition d’une fonction, fichier1.cpp :

extern int varGlobal;

void fonctionExterne(int, float);

int main(void) {
    fonctionExterne(4, 2); /* Dans ce cas là, à la compilation,
                            * tout se  passe bien, mais ça plante
                            * à l'édition de liens. Pour que ça 
                            * fonctionne, il faudrais un fichier en
                            * plus qui définit fonctionExterne. */
    varGlobal = 3;

    return 0;
}

Exemple d’un autre fichier fichier2.cpp :

int varGlobal = 4;

void fonctionExterne(int a, void b) {
    a = 0;
    b = 1.;
}

On peut donc compiler sans problème maintenant
g++ fichier1.cpp fichier2.cpp

On utilises un pointeur d’une classe A vers une classe B :

#include<iostream>

class B; // on déclare la classe B pour qu'elle soit utiliser dans la classe A 

class A {
    B* pb;
};

class B {
    A* pa;
}
int main(void) {
    
    return 0;
}

La visibilité d’un identificateur va de l’endroit où est créé (bloc/fonction/fichier) jusqu’à la fin du bloc/fonction/fichier.

Un espace de nom est toujours définit hors de toute fonction. Il “couvre” les identificateurs créé à l’intérieur.

Exemple

namespace monEspace {
    int maVariable = 0;
}

int main() {
    // maVariable = 1; // -> Erreur
    monEspace::maVariable = 1; // Ok

    return 0;
}

Un même espace de nom peut être complété en plusieurs fois.

Illustration

namespace monEspace {
    int a;
    void f(void);
}
...
namespace monEspace {
    int b;
    ...
}

On peut définir des alias d’espace de nom.

Exemple

namespace monGrandEspaceDeNom {
    int i;
    ...
}

namespace mgedn = monGrandEspaceDeNom;

mgedn::i = 3; // ok alias

On peut importer dans le bloc/fonction/fichier courant tout les identificateurs d’un espace de nom avec using namespace MonEspace (utile avec std).

On peut imbriquer les espaces de nom.

Exemple

int i;
namespace A {
    int i = 1;
    namespace B {
        int i = 2;
    }
}
... i;       // fait allusion au i qui vaut 0
... A::i;    // fait allusion au i qui vaut 1
... A::B::i; // fait allusion au i qui vaut 2

Exemple un peu plus complet

#include<string> // inclu std::string
#include<iostream>
#include<.....> // inclu monEDN::string

using namespace std;

class B {
    public:
        static int a;
};

namespace A {
    namespace B {
        int i = 0;
    }
    int i = 2;
}

int i = 1;

int main(void) {
    using namespace A;
    cout << A::B::i << endl;
    A::B::i = 4;
    cout << A::B::i << endl;
    // cout << i << endl; // on ne sais pas a quelle "i" on fait allusion

    return 0;
}