Les Classes
les structures en C (struct)
regroupent des variables : structuration de l'analyse
mais
• problèmes de cohérence
• problèmes de sécurité d'accès
• problèmes de syntaxe d'utilisation
limitation des structures
cohérence
exemple : taille utile de tableaustruct s_tablo{
long tab[100];long util;
};
taille gérée "à la main" dans le programme
limitation des structures
or : information a priori en lecture seule
taille mise à jour en fonction des opérations effectuées.
on peut tout de même faire :
struct s_tablo t_tab;
t_tab.util = 142; ne correspond à aucune opération
valeur invalide car > 100
limitation des structures
problème de syntaxe :
opérateurs et fonctions standard non applicables
écrire des fonctions spécifiques à cette structure mais fonctions non distinguables a priori
Sécurisation des accès
dans une classe C++ :
les membres de la classe ont une accessibilité :
public ou private (par défaut)
les struct du C ont tous leurs champs public.
Intégration des fonctions
distinction champ/membre
dans une classe C++ : les fonctions font partie de la classe : fonctions membres
classe : champs+fonctions = membres de la classe
tout membre a une accessibilité
Utilisation des membres
• les membres public peuvent être utilisés dans du code hors de la classe
• les membres private ne peuvent être utilisés que dans du code à l'intérieur de la classe
contrôle de ce qui peut être programmé
Rédiger une classeclass ma_classe{
public : // membres publicprivate : // membres private
};
int main(){
ma_classe var;
// instructions}
exemple avec Dev
Appel de fonction membre
accès à un membre comme pour les struct
. pour accéder à un membre d'une variable de la classe
-> pour accéder à un membre via un pointeur
exemple avec Dev
Appel de fonction membre
avantage : simplification des appels, plus de fonctions spécifiques n'importe où dans le code
fonction associée à l'objet qui l'appelle
référencé dans la fonction : this
Fonctions spéciales
Éviter les variables non initialiséesen C : pas de contrôle
en C++ : fonction spéciale à ce rôle pour les classes
le constructeur
porte le nom de la classe associée
Fonctions spéciales
appelé automatiquement à la définition de la variable.en général, accessibilité public
class x{
public :x() {//code à effectuer}// autres membres public
private : // membres private};
exemple avec Dev
Fonctions spéciales
rôle : initialiser les membres de classe
pas besoin de fonction init() à appeler de manière explicite
possibilité de :• paramètres• paramètres par défaut• surcharge (plusieurs constructeurs)
Fonctions spéciales
appel de constructeur avec paramètres
classe objet(paramètres);
exemple :class x{
public : int j;x(int i){j=i};
};
dans main() : x toto(4);
Fonctions spéciales
un exemple avec un programme
la classe Complexe
avec plusieurs constructeurs
c'est parti !
Membres de type pointeur
création de variable : constructeur
gestion des membres de type : pointeur
retour sur le tableau avec taille utile
constructeur avec paramètre pour taille utile :
réaliser une allocation dynamique
Membres de type pointeurclass tablo{
private : long util;double *valeurs;
public :tablo(long nb) // constructeur{
util=nb;
if (util<=0){
util = 0;valeurs = null;
}else{
valeurs = new double[util];}
}
// autres fonctions membres}
Membres de type pointeurclass tablo{
public :
…
void afficher(){ for(long cpt=0; cpt < util; cpt++) {
cout << "valeurs[" << cpt << "] = " << valeurs[cpt] << endl; }
return;}
}
le tableau dynamique est toujours bien initialisé (tester le résultat de new)
Membres de type pointeur
libérer l'espace alloué ?
quand ?
de quelle manière ?
lorsque l'objet est détruit
par l'appel automatique à une fonction membre : le destructeur
Destructeur
porte le nom de la classe précédé de ~
• pas de type de retour
• pas d'arguments
• pas de surcharge
Destructeur
exemples :
classe complexe :~complexe(){} // car rien à faire
classe tablo :~tablo(){
if (valeurs != null){
delete[] valeurs;}
}
new/delete
utilisés pour créer des tableaux d'objets
new : alloue de la mémoireappelle le constructeur
delete : appelle le destructeurlibère la mémoire allouée
exemple avec Dev
Copie d'objets
opération fréquente toujours implicite :
passage de paramètres,
création d'un objet à partir d'un autre
classe objet1;
classe objet2(objet1); // OK
classe objet2 = objet1;
il ne s'agit pas d'une affectation !
Copie d'objets
risquée si un membre est un pointeur !
écrire un constructeur par recopie, le rendre explicite
classe(const classe& paramètre);
passage de const & ?
Copie d'objets
évite le partage de contenu
systématique lorsque la classe a un membre de type pointeur.
Rédaction de classe
partie interface
partie implémentation (code)
séparation en .h / .cpp
prototype et définitions de membres
code des fonctions membres
Rédaction de classe
dans le fichier .cpp, le nom de la fonction membre inclue la classe à laquelle elle appartient[type] classe::fonction(paramètres){
code;[return;]
}
:: résolution de portée
exemple avec Dev
Surcharge des opérateurs
force du C++ : modifier la syntaxe
définir les opérateurs standard pour la classe
opérateur = fonction
syntaxe cohérente
<< et >> toujours surchargés (ou presque)
Surcharge des opérateurs
opérateurs surchargeables :
arithmétiques : + - * / ++ -- %
logiques : && || < <= > >= == !=
autres : [] = << >> -> new delete
Surcharge des opérateurs
surcharge des E/S : << et >>
pas des fonctions membres !
pourtant, doivent accéder aux membres private.
déclarées comme fonctions amies
friend
Surcharge des opérateursclass point2d // pour des graphiques en 2D{ private :
double x,y; public :
point2d(double=0.0, double=0.0);~point2d();point2d(const point2d&);
friend ostream& operator<<(ostream &, const point2d&);};
code de la fonction :ostream& operator<<(ostream &os, const point2d &p){
os << "(" << p.x << "," << p.y << ")";return os;
}
Surcharge des opérateursclass point2d // pour des graphiques en 2D{ private :
double x,y; public :
point2d(double=0.0, double=0.0);~point2d();point2d(const point2d&);
friend istream& operator>>(istream &, point2d&);// pas de const point2d& !!!
};
code de la fonction :istream& operator>>(ostream &is, point2d &p){
is >> p.x >> p.y;return is;
}exemple avec Dev
les nombres complexes
redéfinir les opérateurs arithmétiques
les nombres complexes
en faire une classe se comportant comme un type de base
les opérateurs arithmétiques ont un sens pour cette classe
les nombres complexes
2 possibilités
complex operator+(const complex&);
friend complex operator+(const complexe &, const complexe &);
fonction membre
fonction amie
les nombres complexes
différence ?complex z1, z2;
cout << z1+z2;
+ fonction membre :
z1.operator+(z2);
+ fonction amie :operator+(z1,z2);
et l'opérateur << ?
les nombres complexes
En fait :
cout << z1+z2;
operator<<(cout,z1.operator+(z2));
ou
operator<<(cout,operator+(z1,z2));
il n'y a que des appels de fonctions !
les nombres complexes
choix d'une fonction amie
fonction membre : l'opérande de gauche doit être de la classe dont l'operator est membre :pas de conversion possible.
fonction amie : les deux opérandes sont symétriques
les opérateurs surchargés
implémentation d'un opérateur
complex operator+(const complex &z1, const complex &z2){
return complex(z1.re+z2.re,z1.im+z2.im);}
exemple avec Dev
l'opérateur =
presqu'identique au constructeur par recopie
nécessaire lorsque l'on traite des pointeurs
mais bug très vicieux
le cas de l'auto affectation !
l'opérateur =class toto{// du code ici};
class w{ private :
toto *p; // pointe sur un objet de classe toto
public : // constructeurs, destructeur, surcharges classiques
w& operator=(const w& source){
if (values){
delete p;}
p = new toto(*(source.p)); // aie aie aie….
return *this;}
}
l'opérateur =
tester si this est égal à &source !
if (this==&source) return *this;
Objets temporaires
créés dans des expressions, durée de vie très brève
Conclusion
Écriture de classes robustes
• sécurité d'accès
• facilité d'utilisation
• initialisation garantie