Vous êtes sur la page 1sur 36

M.

Afilal

Les classes
Une classe est une description dune famille dobjets, qui ont Mmes attributs
Mme mthodes Une classe est: une moule dun ensemble dobjets qui partagent une structure commune (les attributs) et un comportement commun (les mthodes). Une classe correspond aussi a un type de donne comme int, double, elle correspond au type des objets qui lui sont lis.

Spcification

M.Afilal

Classe CompteBancaire ..
Nom de la classe CompteBancaire

Attributs
Oprations

- solde # numCompte
+ deposer() + retirer()

private

protected
public

Une classe est structure en 3 partie (les modes daccs): La partie publique: contient les dclarations visibles tout utilisateur de cette classe. La partie protge: contient les dclarations visibles uniquement par les classes hritant de la classe de base. La partie prive: contient les dclarations invisibles toute autre classe M.Afilal diffrente de la classe de base.

Instance ou objet dune classe


Chaque objet appartient une classe On dit que: obj1 est un objet de la classe X ou Obj1 est une instance de la classe X

CompteBancaire instanciation

classe

compte001 : CompteBancaire

Instance ou objet

solde : 1000 numCompte: 1234


M.Afilal

Les classes
Une classe (mot cl class) est une structure particulire, pour laquelle on prcise si les membres (champs) et les fonctions membres sont publics, privs ou protgs (mots cls public, private ou protected): Cest le mcanisme de protection ou encapsulation des donnes Dans les structures, en gnral, tous les membres ou champs sont publics par dfaut mais private pour les classes. Daprs le principe dencapsulation: on ne peut accder aux donnes prives que par lintermdiaire des mthodes publics (en gnrale). On considrera donc, en gnral, les champs comme membres prives et les mthodes comme membres publics. une classes , comme les structures, est utilise aussi comme un type de donne, comme int, char...

M.Afilal

Les constructeurs
Les constructeurs se sont des fonctions membres spciales appeles la cration d'un objet d'une classe Ce sont des fonctions dont le nom est celui de la classe Qui ne retournent rien mme pas un void Qui peuvent contenir ou pas des arguments Qui permettent dinitialiser les champs de la classe Attention aux pointeurs, aux tableaux et tout objet qui doit sallouer dynamiquement de la mmoire, il faut toujours les initialiser dans les constructeurs car sinon cas des pointeur : pas dinitialisation dun pointeur, le pointeur pointera vers une adresse au hasard, comme une zone de code quelconque, ce qui serait dramatique pour lapplication. le constructeur par dfaut (constructeur sans arguments) est appel automatiquement la cration d'un objet (si pas de constructeur avec arguments)

M.Afilal

Tableau dobjets
Proprit: Dans le cas dun tableau dobjet, le constructeur par dfaut est appel la cration de chaque lment du tableau. Point tab[3]; void main(){ Point *tabPoint = new Point[3]; for(int i = 0; i < 3; i++){ tabPoint[i].X =4 + i; // pb si X et Y sont private tabPoint[i].Y =8 * i; } cout << " coordonnes du point la deuxime position: << tabPoint[1].X << " << tabPoint[1].Y <<endl; delete[] tabPoint;

M.Afilal

Le destructeur
Un destructeur est une fonction membre qui est automatiquement appele au moment de la destruction dun objet, avant la libration de lespace mmoire associe lobjet. La destruction des objets se fait de manire identique aux variables ordinaires : la fin du programme pour les objets statiques, laide de linstruction delete ou la fin du bloc ou de la fonction pour les objets dynamiques. La libration de la mmoire allouer dynamiquement tant confi dans ce cas au destructeur. le destructeur est indispensable ds quun objet ou champs est amen allouer dynamiquement de la mmoire. Par convention: le destructeur porte le mme nom que sa classe, prcd du symbole du tilde (~). Par dfinition il ne comporte aucun argument ne renvoi pas de valeur (mme pas un void). Exemple : ~Point() ;// destructeur de la classe Point
M.Afilal

Les classes
class Point{ private: int x; int y; public: Point(); ~Point(); }; Point::Point(){x = 0;y = 0;} Point::~Point(){} int main(int argc, char* argv[]){ Point p3; return 0; }

M.Afilal

Surdfinition ou surcharge dune fonction


En gnral, une fonction se dfinit par : son nom, sa liste type de paramtres formels, le type de la valeur qu'elle retourne. Seuls les deux premiers critres sont discriminants. On dit qu'ils constituent la signature de la fonction. On peut utiliser cette proprit pour donner un mme nom des fonctions qui ont des paramtres diffrents et de les utiliser dans le mme programme: cest la surdfinition ou la surcharge de fonction

M.Afilal

Surdfinition ou surcharge dune fonction


int somme( int n1, int n2){ return n1 + n2; } int somme( int n1, int n2, int n3){return n1 + n2 + n3; } double somme( double n1, double n2){ cout << somme de double<<endl; return n1 + n2; } void main() { cout << "1 + 2 = " << somme(1, 2) << endl; cout << "1 + 2 + 3 = " << somme(1, 2, 3) << endl; cout << "1.2 + 2.3 = " << somme(1.2, 2.3) << endl; } Le compilateur slectionnera la fonction appeler en fonction du type et du nombre des arguments qui figurent dans l'appel de la fonction. Attention, il y a des conversions implicites, dans le cas o largument pass la fonction nest pas dfini dans le prototype de la fonction char et short int float - double
M.Afilal

Surdfinition ou surcharge dune fonction


Autres Exemples: void sosie(int) ; //sosie I void sosie(double) ; //sosie II void sosie(int &) ; //la dernire ligne conduit une erreur car il y a une ambigut pour le compilateur avec sosieI char c ; float y ; void main(){ sosie(c) ; // appel de sosie I aprs conversion de c en int sosie(y) ; // appel de sosie II aprs conversion de y en double sosie(d); // appel de la fct sosieI aprs conversion de d en int }

M.Afilal

Surdfinition ou surcharge dune fonction


Autres Exemples: struct Personne {double age; int tel; char* nom; }; struct Ville {int departement; char nomVille[200];}; void f(Personne pers); void f(Ville ville); Pas derreur la compilation : les types des deux structures sont diffrents void f2(char *str) { /* ... */ } void f2(char ligne[80]) { /* ... */ } Erreur: redfinition de la fonction f, char * et char [80] sont considrs de mme type : des pointeurs de type char int somme1(int n, int m) {return n+m;} int somme1(const int n, const int m) { return n+m; } Erreur: la liste de paramtres dans les dclarations des deux fonctions n'est pas assez divergente pour les diffrencier
M.Afilal

Les classes
class Point{ private: int x; int y; public: Point(); Point(int, int); ~Point(); Point somme (Point*); Point somme (Point&); void affiche(); };

M.Afilal

Les classes
Point::Point(){ x = 0;y = 0; }

Point::Point(int a, int b){ x = a; y = b; }


Point::~Point(){} Point Point::somme(Point* a){ Point p; p.x = x + a->x; p.y = y + a->y; return p; } Point Point::somme(Point& a){ Point p; p.x = x + a.x; p.y = y + a.y; return p; } void Point::affiche(){ cout<<"les coordonnes du point sont: ("<<x<<", "<<y<<")"<<endl; }
M.Afilal

Les classes
int } main(int argc, char* argv[]){ Point p1(2,2); Point p2(5,3); Point p3; p1.affiche(); p3.affiche(); (p2.somme(&p1)).affiche(); (p2.somme(p3)).affiche(); return 0;

M.Afilal

Constructeur par recopie ou de recopie ou de copie


Reprenons notre classe Point prcdente. Soit la dclaration dun objet A : Point A(3,5) ; Il est possible de dclarer un nouvel objet B et de linitialiser aux valeurs de lobjet A par Point B = A ; //initialisation Il y a deux manires diffrentes qui permettent dinitialiser un objet via les valeurs dun autre objet: Il nexiste pas de constructeur prvoyant ce cas de dclaration: dans ce cas un traitement par dfaut est prvu. Il existe un constructeur prvoyant ce cas de dclaration et il sera alors utilis.

M.Afilal

Constructeur par recopie


Sil nexiste pas de constructeur appropri. Cela signifie quil nexiste pas, dans la classe Point, de constructeur un seul argument de type Point: le compilateur va donc mettre en place une recopie des valeurs de lobjet A aux valeurs de lobjet B, aprs cration de celui ci (comme laffectation entre variable de mme type). Un problme se pose lorsque les objets contiennent des pointeurs sur des emplacements allous dynamiquement : les valeurs des pointeurs seront recopies mais pas les emplacements points: c.a.d: les pointeurs pointent vers la mme adresse sachant quils ont eux des adresses diffrents. Dans ce cas, C++ utilise un constructeur par recopie par dfaut effectuant la simple recopie des membres donnes. Remarque Mme sil existe un constructeur usuel pour la classe, cest le constructeur par recopie par dfaut qui sera utilis.
M.Afilal

Constructeur par recopie


Sil existe un constructeur appropri Le C++ imposant ce constructeur(constructeur par recopie): Que son unique argument soit transmis par rfrence. Il sera donc de la forme: Point(Point &) ou Point(const Point &). Ce constructeur sera appel de faon habituelle (aprs cration de lobjet): mais cette fois ci, aucune recopie nest mise en place automatiquement : cest au constructeur de recopie de la prendre en charge.

M.Afilal

Exemple: Constructeur par recopie par dfaut


class tab{ int nbelem ; // nombre dlment dans le tableau int *adr ; public : tab(int n) { nbelem = n ; adr = new int[nbelem] ; // allocation dynamique du tableau cout << ++ constructeur usuel adresse de lobjet cre = << this << endl ; cout << adresse tableau= << adr << endl ; } ~tab( ){ cout << destructeur adresse objet dtruit = << this << endl ; cout << adresse tableau = << adr << endl ; if(adr) delete[] adr ; } }; void main( ){ tab t1(5) ; // cration de t1 par le constructeur usuel tab t2 = t1 ; // cration de t2 par appel du constructeur par //recopie par dfaut sur lobjet t1 // ou bien, tab t2(t1) ; }
M.Afilal

Exemple: Constructeur par recopie par dfaut


Donne comme affichage : ++constructeur adresse objet = 0x8F87FFF2 adresse tableau = 0x8F870D98 //t1 -- destructeur adresse objet = 0x8F87FFEE adresse tableau = 0x8F870D98 //dest. T2 -- destructeur adresse objet = = 0x8F87FFF2 adresse tableau = 0x8F870D98 //dest. T1 Daprs les rsultats de lexcution du programme, on constate que lobjet t2 a bien t cr, avec recopie des valeurs de lobjet t1. A la fin du programme principal, lappel du destructeur libre lemplacement point par adr pour lobjet t1, puis libre le mme emplacement pour lobjet t2 : donc le mme emplacement mmoire est libr deux fois, ce qui est compltement anormal !!! La situation peut se schmatiser de la faon suivante :
M.Afilal

Exemple: Constructeur par recopie par dfaut


Cette situation montre galement toute modification du tableau de lobjet t1 entranera donc une modification du tableau de lobjet t2 et inversement. Pour viter ce problme, il faut crer un constructeur par recopie.

Objet : t1

nbelem
FFF2

adr

0D98

Objet : t2
FFEE

nbelem adr
M.Afilal

Constructeur par recopie


Dfinition dun constructeur par recopie Le constructeur par recopie devra: crer un nouvel objet avec recopie des membres donnes, mais surtout avec un nouvel emplacement pour le tableau dynamique ou des zones alloues dynamiquement. La situation deviendra alors la suivante :

M.Afilal

Constructeur par recopie

Objet : t1

0D98
nbelem FFF2 adr

Objet : t2
nbelem FFEE

0DA6

adr

M.Afilal

Exemple: Constructeur par recopie


On ajoute lexemple prcdent la fonction suivante (constructeur par recopie) tab(const tab& v) // constructeur par recopie { nbelem = v.nbelem ; adr=new int[nbelem]; // cration du nouveau tableau for(int i=0 ; I < nbelem ; i++) adr[i]=v.adr[i]; // recopie de lancien tableau cout << ++ constructeur par recopie adresse objet cre = << this << endl ; cout << adresse tableau= << adr << endl ; } Donne comme affichage : ++constructeur adresse objet = 0x8F87FFF2 adresse tableau = 0x8F870D98 //t1 ++constructeur adresse objet = 0x8F87FFEE adresse tableau = 0x8F870DA6 //t2 --destructeur adresse objet = 0x8F87FFEE adresse tableau = 0x8F870DA6 //dest.t2 -- destructeur adresse objet = = 0x8F87FFF2 adresse tableau = 0x8F870D98M.Afilal //dest. t1

Constructeur par recopie


int main(){ Tableau tab(4); tab.saisieTableau(); tab.afficheTableau(); cout<<"**teste du constructeur par recopie**"<<endl; Tableau tabConst(tab); tabConst.afficheTableau(); return 0; } Remarque Le constructeur par recopie permet de rgler le problme de linitialisation dun objet par un autre objet de mme type au moment de sa dclaration. Cela ne rsout pas pour autant le problme qui se pose en cas daffectation entre des objets de mme type (exp : t1 = t2), o il faut, dans ce cas, surdfinir loprateur = (ce type de surdfinition sera vu ultrieurement)

M.Afilal

Liste d'Initialisation dun constructeur


Soit la classe : class Y { /* ... */ }; class X { public: X(int a, int b, Y y); ~X(); // .... private: const int _x; Y _y; int _z; }; X::X(int a, int b, Y y) { _x = a; // ERREUR: l'affectation une constante est interdite _z = b; // OK : affectation _y = y; // fait appel loprateur daffectation, problme pour les partie dynamique (il faut surcharger loprateur ou utiliser les constructeurs dune faon intelligente). }; Questions: Comment initialiser la donne membre constante _x Comment appeler le constructeur de la classe Y afin dinitialiser lobjet membre _y Rponse : la liste d'initialisation.

M.Afilal

Liste d'Initialisation dun constructeur


La phase d'initialisation dun objet utilise: une liste d'initialisation qui est spcifie dans la dfinition du constructeur. Syntaxe : nom_classe::nom_constructeur( args ... ) : liste_d_initialisation{ // corps du constructeur} Exemple: X::X(int a, int b, Y y) : _x( a ) , _y( y ) , _z( b ) { // rien d'autre faire dautre pour linitialisation } L'expression _x( a ) indique au compilateur d'initialiser la donne membre _x avec la valeur du paramtre a. L'expression _y( y ) indique au compilateur d'initialiser la donne membre _y par un appel au constructeur adapt (avec l'argument y ) de la classe Y, avec. y est un objet de la classe Y (appel constr par recopie) Ou y est un ensemble de valeurs des champs de la classe Y (appelM.Afilal de constr ordinaire)

Exemple
class Personne{ private: char *nom; double age; public: Personne(); Personne(char *, double) ; Personne(const Personne&) ; ~Personne(); void affiche() ; };

M.Afilal

Exemple
Personne::Personne(){ cout << "constructeur par dfaut: " << endl; nom = new char[256]; strcpy(nom, "Albertine") ; age = 99; } Personne::Personne(char *nomPers, double agePers){ cout << "constructeur avec argument: " << endl; nom = new char[strlen(nomPers)+1]; strcpy(nom, nomPers) ; age = agePers; } void Personne::affiche(){ cout << "nom de la personne est: " << nom << " " << "son age est: " << age << endl; } Personne::Personne(const Personne& pers){ cout << "constructeur de recopie: " << endl; nom = new char[strlen(pers.nom)+1]; strcpy(nom, pers.nom) ; age = pers.age; } Personne::~Personne(){ if(nom) delete[] nom; }
M.Afilal

Suite exemple
#include " Personne.h" class Etudiant{ public: Etudiant(char *, double) ; Etudiant(const Personne&) ; ~ Etudiant() ; private: Personne *p1 ; Personne p2 ; static Personne p3; // variable partag par tous les objets }; Question: Comment initialiser p1, p2 et p3 ? variable de classe: p3 Personne Etudiant :: p3(Albertine,20) ; // on ne rpte pas le mot cl static
M.Afilal

Suite exemple
variables dinstance P1 et P2: Etudiant :: Etudiant(char *nomPerso, double d ) : p1(new Personne(nomPerso, d)), p2(nomPerso, d){ // p1 est un pointeur, donc on utilise loprateur new // dans ce cas: y=(nomPerso, d); appel constructeur avec deux arguments // pas de new pour p2 car cest un objet } Etudiant:: Etudiant(const Personne& pers ) : p2(pers), p1(new Personne(pers)){ p2.affiche() ; p1->affiche() ; // dans ce cas: y = pers; appel du constructeur par recopie } Etudiant :: ~ Etudiant( ){ if(p1) delete p1 ; }
M.Afilal

Liste dinitialisation dans un constructeur


Pour initialiser un objet, on peut utiliser la liste dinitialisation donne dans le constructeur. La liste dinitialisation est utile quand: on est amen initialiser un attribut dune classe dont le type est un type dune autre classe. On a un attribut constant. On utilise lhritage entre classes: Afin de passer des arguments aux constructeurs de classes de base via le constructeur de la classe drive.

M.Afilal

TD
class Personne{

};

char *nom; double age; public: Personne(); Personne(char *, double) ; Personne(const Personne&) ; virtual ~Personne(); void affiche() ; char* getNom(); double getAge(); void setNom(char*); void setAge(int); void affiche();

M.Afilal

TD
#include "Personne.h" class Etudiant { public: Etudiant(char *, double) ; Etudiant(const Personne& ); Etudiant(const Etudiant& );// A FAIRE virtual ~ Etudiant() ; void setP3(Personne&); void setP2(Personne&); void affiche(); private: Personne *p1 ; Personne p2 ; static Personne p3; };

M.Afilal

TD
cout<<" ---- teste de la classe Personne ----"<<endl; Personne pers1("ahmed",14); Personne*pers2 = new Personne("Nadine",99); pers1.affiche(); pers2->affiche(); cout<<" ---- teste mthode inline ----"<<endl; if(pers2) delete pers2; cout<<" ---- teste de la classe Etudiant ----"<<endl; Etudiant etud1("Atikosse", 55); Etudiant *etud2 = new Etudiant(pers1); Personne persStat("changeStatic", 66); etud1.setP3(persStat); etud2->affiche(); etud2->setP2(Personne("nomModif", 22)); cout<<" ---- teste constructeur par recopie ----"<<endl; Etudiant etud3(etud1), *etud4 = new Etudiant(*etud2); etud4->affiche(); if(etud4) delete etud4; if(etud2) delete etud2;
M.Afilal