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 variables/objets
- les fonctions
- les types
Les identificateurs peuvent être créer à partir de :
- définitions
- déclarations
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;
}