Vous êtes sur la page 1sur 44

Wikiversité

Langage C++/Classe
< Langage C++

La classe
En programmation orientée objet, tout est basé sur le concept de
la classe. La classe est une entité autonome capable de maintenir,
une fois instanciée (définie), la cohérence des données qu'elle est
chargée d'entretenir. (nous mettrons en évidence la syntaxe dans
la partie implémentation)

Les visibilités : niveaux de visibilité dans une classe

Il existe trois niveaux de visibilité dans une classe :

Privé (Niveau par défaut) : Permet de masquer complètement


les données et méthodes à des classes tierces et même aux
classes dérivées. On parle d'encapsulation (peut être utilisé par
les méthodes mais est surtout destiné aux variables d'une
classe).
Protégé : permet de partager des données uniquement aux
classes dérivées. (Normalement uniquement utilisé pour les
méthodes)
Public : permet de partager les données avec toutes les classes
tierces. (Normalement uniquement utilisé pour les méthodes)

Les attributs : variable de classes

La classe est une entité qui peut être composée de variables


internes que l’on nomme attributs membres.

La théorie veut que les attributs d'une classe ne soient


accessibles directement qu’à cette classe. Bien qu'en C++ il soit
possible de définir des attributs membres de visibilité publique ou
protégée, il est normalement indispensable de rendre les attributs
membres privés (je n'ai jamais eu à rendre publiques ou même
protégés des attributs).
En effet le paradigme-objet étant de rendre la classe responsable
de la gestion de ses attributs pour assurer la gestion correcte et la
cohésion des données, il serait mal vu qu'une autre classe accède
malencontreusement à ces attributs et vienne bouleverser
l'organisation que la classe permet de maintenir entre eux. Quand
une classe privatise un attribut on dit qu'elle l'encapsule.

Les méthodes : méthodes de classes

Nous avons déjà vu les méthodes auparavant.

Les méthodes déterminent le comportement qu'une classe est


capable de réaliser. La classe possède au moins trois méthodes
spéciales :

Un constructeur sans paramètres appelé aussi constructeur par


défaut ou, selon le cas, un constructeur paramétré qui oblige à
fournir des paramètres pour créer la classe.
Un constructeur par copie qui prend en paramètre une
référence sur la même classe (dans la majorité des cas elle est
fournie par défaut par le compilateur mais il peut être
fréquemment nécessaire de la définir manuellement).
Un destructeur qui est chargé d'appliquer un traitement pour
éventuellement nettoyer la mémoire. Bien qu’il soit souvent
vide, l'implémenter explicitement et systématiquement permet
de faire fonctionner le mécanisme d'héritage polymorphe.

Les méthodes donnant accès aux attributs sont appelés suivant le


sens d'accès :

Des accesseurs pour les méthodes accédant en lecture seule.


Des mutateurs pour les méthodes accédant en écriture seule.
Des propriétés pour les méthodes accédant en écriture et en
lecture.

La théorie veux que tout attribut qui aurait besoin d’être transmis
ou modifié, le soit par l'une de ces méthodes d'accès. (Je n'ai
jamais eu à faire autrement.) Les méthodes définissent aussi
l'interface d'une classe.
Généralisation de classes

En programmation orientée objet, on peut structurer une


hiérarchie de classes en arborescence. Les classes du sommet de
l'arbre sont les classes les plus abstraites et générales. Les
classes les plus profondes sont les plus concrètes et les plus
spécialisés.

Pour illustrer ces propos supposons les figures suivantes :

Carré
Rectangle
Parallélogramme
Losange
Quadrilatère
Cercle
Ovale

Imaginons maintenant que nous devions réaliser des classes


basées sur ces figures. Supposons que chaque classe doit être
capable de dessiner. Supposons aussi que nous devions gérer
chacune de ces classes avec le même (et unique) pointeur et
appeler la même méthode pour le dessin de chaque classe.

Dans les figures imposées on peut voir que "Carré" est un cas
particulier de (ou "une sorte de") "Rectangle" qui est lui-même un
cas particulier du "Parallélogramme" qui est lui-même un
"Quadrilatère". Quant à "Losange" c’est un "Quadrilatère".

On peut voir aussi que "Cercle" est un cas particulier de "Ovale".

Cependant rien ne lie Ovale et Quadrilatère.

Nous allons donc devoir généraliser Ovale et Quadrilatère en


"Figure"

Ainsi Quadrilatère et Ovale sont des Figures, ainsi un pointeur sur


Figure est capable de manipuler n’importe quelle classe sous-
jacente, puisque, après tout, un carré est une figure tout comme
un cercle.

Traitons maintenant le problème de la méthode unique. En fait


depuis que l’on a créé la classe Figure ce n'est plus un problème.
En effet il suffit de définir la méthode "Dessine()" dans la classe
Figure pour que toutes les autres classes en héritent.

Abstraction de classes

Lors de généralisations successives il est courant de se rendre


compte qu'une classe est trop "abstraite" pour avoir suffisamment
de données exploitables pour pouvoir en générer une instance.
C'est le cas pour notre classe "Figure". En effet elle est trop
générique et rien d'intéressant ne peut en sortir, cependant elle
fournit une interface que toutes les autres classes devront
reproduire fidèlement. La méthode "Dessiner" ne représente pas
grand chose pour une Figure. Nous ne pouvons pas décrire de
comportement pour cette méthode dans cette classe. Nous ne
pouvons donc pas instancier la classe car cela n'aurait pas de
sens. Nous allons donc devoir rendre cette classe abstraite. Cela
signifie que la classe n’est pas instanciable en l'état mais qu'une
classe héritée non abstraite peut être interprétée comme cette
classe (via l'utilisations de pointeurs ou de références).
Héritage de classes

L'héritage est la faculté qu’à une classe de pouvoir transmettre


ses attributs et méthodes à ses classes dérivées et, sous
certaines conditions, permettre à ses classes dérivées de redéfinir
ses méthodes pour pouvoir les améliorer et les spécialiser.

Tout d’abord il faut savoir qu'en C++ une classe dérivée reçoit
toujours une copie de l'intégralité des attributs et des méthodes
de sa classe ancêtre. En C++, bien que l’on puisse choisir la façon
dont sont copiés les membres de la classe ancêtre, la théorie-
objet veux que l’on hérite toujours des classes ancêtres de
manière publique afin que tous les membres publics de la classe
ancêtre soient aussi disponibles de manière publique dans la
classe dérivée. L'héritage permet de ne pas réécrire éternellement
les mêmes codes, de réutiliser les objets, de pouvoir les
spécialiser et mettre en œuvre le polymorphisme de classe.

Polymorphisme de classes
Le polymorphisme en informatique se traduit par la capacité qu'a
un pointeur de classe ancêtre présentant une interface donnée, à
appeler la méthode de l'instance de la classe dérivée
correspondant à la méthode de la classe ancêtre. En C++ la mise
en œuvre du polymorphisme se fait à l'aide du mot clé "virtual".
Dans la pratique et pour reprendre l'exemple vu précédemment :

Si l’on créé un pointeur sur Figure que l’on lui assigne l'adresse de
l'instance d'un carré et que l’on demande au pointeur-figure de se
dessiner alors le pointeur va appeler la méthode virtuelle et par le
biais de l'héritage virtuel appeler la méthode implémentée dans la
classe Carré.

Implémentation

Les classes sont donc la représentation logique du concept


d'objet. Voici en C++ comment implémenter ces classes
conformément à la théorie de l'objet.

Définition
Syntaxe:

class <NomNouvelleClasse> :
[public: <ClasseAncêtre>[,
<AutreClasseAncêtre>][, ...]]
{
[ [<Visibilitée>:]
<TypeAttribut1>
<NomAttribut1>;]
[<Visibilitée>:]
<TypeAttributN>
<NomAttributN>;] ]
[<Visibilitée>:]
<TypeMethode1> <NomMethode1>
(<TypeParamettre>
<NomParamettre>[ =
<ValeurParDefaut>][, ...]);
[ [<Visibilitée>:]
<TypeMethodeN> <NomMethodeN>
(<TypeParamettre>
<NomParamettre>[ =
<ValeurParDefaut>][, ...]); ]
};

Où <NomNouvelleClasse> est le nom de la classe,


<ClasseAncêtre> est une classe ancêtre tout comme
<AutreClasseAncêtre> et sont facultatives si la classe n'a pas à
avoir d'ancêtre, <TypeAttribut1> et <TypeAttributN> sont les types
des attributs, <NomAttribut1> et <NomAttributN> sont les noms
des attributs, les attributs sont facultatifs, <TypeParamettre> et
<NomParamettre> sont les paramètres des méthodes de la
classe, <TypeMethode1> et <TypeMethodeN> sont les types de
retours des méthodes de la classe, <NomMethode1> et
<NomMethodeN> sont les noms des méthodes de la classe, ,
<Visibilitée> peut prendre trois valeurs: public, protected ou
private (par défaut). Un membre déclaré public peut être manipulé
par n’importe quelle classe, un membre protected ne peut être
manipulé que par la classe et ses dérivées tandis qu'un membre
private ne peut être manipulé que par les méthodes de la classe.

Les méthodes sont soit définies directement dans la déclaration


de classe (au quel cas ce sont des Macros), soit définies en
dehors de la déclaration dans un fichier source séparé de la
manière suivante :

Définition

Syntaxe:

<TypeRetour> [<NomClasse>::]<NomMethode>
([<TypeParametre> <NomParametre>[,<...>]])
{
[<Instructions>;]
}

Voici un exemple de la classe la plus simple à réaliser. Il faut dire


aussi qu'elle ne fait strictement rien.
Exemple

dans le ".h"

#ifndef FAINEANTE_H
#define FAINEANTE_H

class Faineante;
{
public:
// Constructeur par
défaut
Faineante();

// Constructeur par
copie
Faineante(Faineante&
pCopie);
// Destructeur
virtual ~Faineante();
// "virtual" active le
polymorphisme
};

#endif //FAINEANTE_H

Dans le ".cpp"

Faineante::Faineante()
{
}

Faineante::Faineante(Faineante&
pCopie)
{
}

Faineante::~Faineante()
{
}

Exemples:

Maintenant reprenons nos exemples de figures de tout à l’heure.

Exemple

dans "Carre.h"

#ifndef Carre_H
#define Carre_H

#include "Rectangle.h"
// Un carré est un rectangle dont toutes les
arrêtes sont égales.
class Carre : public Rectangle
{
public:
// Constructeur paramétré
Carre(double pArrete);
// Destructeur
virtual ~Carre();
virtual void mDessine();
};

dans "Carre.cpp"

#include "Carre.h"

// Constructeur paramétré
// Appelle le constructeur de la classe ancêtre
en le paramétrant correctement
Carre::Carre(double pArrete):Rectangle(pArrete,
pArrete)
{
}

// Destructeur
Carre::~Carre()
{
}

void Carre::mDessine()
{
//Dessine ici le Carre (vrais code de dessin
non pertinent car trop volumineux pour le gain
obtenu sur l’intérêt de la leçon).
cout << "Dessine Carre :\n" << endl;
Rectangle::mDessine();
}

dans "Rectangle.h"

#ifndef Rectangle_H
#define Rectangle_H
#include "Parallelogramme.h"

//Un Rectangle est un Prarallelogramme avec tous


ses angles droits.
class Rectangle : public Parallelogramme
{
public:
Rectangle(double pArreteAB, double
pArreteBC);
virtual ~Rectangle();
virtual void mDessine();
};

dans "Rectangle.cpp"

#include "Rectangle.h"

// Appelle le constructeur de la classe ancêtre


en le paramétrant correctement
Rectangle::Rectangle(double pArreteAB, double
pArreteBC):Parallelogramme(pArreteAB, pArreteBC
90.0)
{
}

// Destructeur
Rectangle::~Rectangle()
{
}

void Rectangle::mDessine()
{
//Dessine ici le Rectangle (vrais code de
dessin non pertinent car trop volumineux pour le
gain obtenu sur l’intérêt de la leçon).
cout << "Dessine Rectangle :\n" << endl;
Parallelogramme::mDessine();
}
dans "Parallelogramme.h"

#ifndef Parallelogramme_H
#define Parallelogramme_H

#include "Quadrilatere.h"

// Un Parallélogramme est un Quadrilatère dont


les cotés parallèles sont égaux.
class Parallelogramme: public Quadrilatere
{
private:
double& mCorrectionAngle(double&
pAngle);

protected:
virtual void mAngleA(double& pAngle);
virtual void mAngleB(double& pAngle);
virtual void mAngleC(double& pAngle);
virtual void mAngleD(double& pAngle);
public:
// Constructeur parametré
Parallelogramme(double pArreteAB, double
pArreteBC, double pAngleA);
// Destructeur
virtual ~Parallelogramme();
// Méthode de dessin des
parallélogrammes.
virtual void mDessine();
};

dans "Parallelogramme.cpp"

#include <iostream>
#include "Parallelogramme.h"

using namespace std;

double& mCorrectionAngle(double& pAngle)


{
// Corriger les dépassements
double vAngleMaximal = 180.0;
pAngle %= vAngleMaximal;
// Si l'angle est
if(pAngle < 0)
{
// Corriger le signe.
pAngle *= -1;
}
return pAngle;
}

virtual void mAngleA(double& pAngle)


{
Quadrilatere::mAngleA(pAngle);
}

virtual void mAngleB(double& pAngle)


{
Quadrilatere::mAngleB(pAngle);
}

virtual void mAngleC(double& pAngle)


{
Quadrilatere::mAngleC(pAngle);
}

virtual void mAngleD(double& pAngle)


{
Quadrilatere::mAngleD(pAngle);
}

// Constructeur paramétré
Parallelogramme::Parallelogramme(double
pArreteAB, double pArreteBC, double
pAngleA):Quadrilatère(pArreteAB, pArreteBC,
pArreteAB, pArreteBC, 0.0, 0.0, 0.0, 0.0)
{
// Dans un Parallélogramme les arrêtes :
// AB = CD et BC = AD.
// Les angles :
// A = C, B = D et A + B + C + D = 360°.
// Ici nous passons par les méthodes de
Parallélogramme pour garantir que les angles
seront inférieur ou égal à 180.

double vAngleMax = 180.0;


this->mAngleA(pAngleA);
this->mAngleB(vAngleMax - this-
>mCorrectionAngle(pAngleA));
this->mAngleC(pAngleA);
this->mAngleD(vAngleMax - this-
>mCorrectionAngle(pAngleA));
}

// Destructeur
virtual Parallelogramme::~Parallelogramme()
{
}
// Méthode de dessin des parallélogrammes.
virtual void Parallelogramme::mDessine()
{
//Dessine ici le Parallelogramme (vrais code
de dessin non pertinent car trop volumineux pour
le gain obtenu sur l’intérêt de la leçon).
cout << "Dessine Parallelogramme :\n" <<
endl;
Quadrilatere::mDessine();
}

dans "Losange.h"

#ifndef Losange_H
#define Losange_H

#include "Quadrilatere.h"

class Losange : public Quadrilatere


{
private:
double& mCorrectionAngle(double&
pAngle);

protected:
virtual void mAngleA(double& pAngle);
virtual void mAngleB(double& pAngle);
virtual void mAngleC(double& pAngle);
virtual void mAngleD(double& pAngle);

public:
Losange(double pArreteAB, double
pArreteBC, double pAngleA);
virtual ~Losange();
virtual void mDessine();
};

dans "Losange.cpp"
#include "Losange.h"

// L'angle maximal d'un angle de losange est :


180°
double& Losange::mCorrectionAngle(double&
pAngle)
{
// Corriger les dépassements
double vAngleMaximal = 180.0;
pAngle %= vAngleMaximal;
// Si l'angle est
if(pAngle < 0)
{
// Corriger le signe.
pAngle *= -1;
}
return pAngle;
}

void Losange::mAngleA(double& pAngle)


{
// Mettre à jour l'angle.

Quadrilatere::mAngleA(mCorrectionAngle(pAngle))
}

void Losange::mAngleB(double& pAngle)


{
// Mettre à jour l'angle.

Quadrilatere::mAngleB(mCorrectionAngle(pAngle))
}

void Losange::mAngleC(double& pAngle)


{
// Mettre à jour l'angle.

Quadrilatere::mAngleC(mCorrectionAngle(pAngle))
}
void Losange::mAngleD(double& pAngle)
{
// Mettre à jour l'angle.

Quadrilatere::mAngleD(mCorrectionAngle(pAngle))
}

Losange::Losange(double pArreteAB, double


pArreteBC, double
pAngleA):Quadrilatere(pArreteAB, pArreteBC,
pArreteBC, pArreteAB, 0.0, 0.0, 0.0, 0.0)
{
// Dans un losange les arrêtes :
// AB = DA et BC = CD.
// Les angles :
// A = C, B = D et A + B + C + D = 360°.
// Ici nous passons par les méthodes de
Losange pour garantir que les angles seront
inférieur ou égal à 180.
double vAngleMax = 180.0;
this->mAngleA(pAngleA);
this->mAngleB(vAngleMax - this-
>mCorrectionAngle(pAngleA));
this->mAngleC(pAngleA);
this->mAngleD(vAngleMax - this-
>mCorrectionAngle(pAngleA));
}

~Losange::Losange()
{
}

void Losange::mDessine()
{
//Dessine ici le Losange (vrais code de
dessin non pertinent car trop volumineux pour le
gain obtenu sur l’intérêt de la leçon).
cout << "Dessine Losange :\n" << endl;
Quadrilatere::mDessine();
}

dans "Quadrilatere.h"

#ifndef Quadrilatere_H
#define Quadrilatere_H

#include "Figure.h"

class Quadrilatere : public Figure


{
private:
double aArreteAB;
double aArreteBC;
double aArreteCD;
double aArreteDA;
double aAngleA;
double aAngleB;
double aAngleC;
double aAngleD;
double& mCorrectionAngle(double&
pAngle);
double& mCorrectionArrete(double&
pArrete);

protected:
void mArreteAB(double& pArrete);
void mArreteBC(double& pArrete);
void mArreteCD(double& pArrete);
void mArreteDA(double& pArrete);

virtual void mAngleA(double& pAngle);


virtual void mAngleB(double& pAngle);
virtual void mAngleC(double& pAngle);
virtual void mAngleD(double& pAngle);

public:
Quadrilatere(double& pArreteAB, double&
pArreteBC, double& pArreteCD, double& pArreteDA
double& pAngleA, double& pAngleB, double&
pAngleC, double& pAngleD);
virtual ~Quadrilatere();
virtual void mDessine();
double mArreteAB();
double mArreteBC();
double mArreteCD();
double mArreteDA();
double mAngleA();
double mAngleB();
double mAngleC();
double mAngleD();
};

dans "Quadrilatere.cpp"

#include <math.h>
#include "Quadrilatere.h"

// L'angle maximal d'un angle de quadrilatère


est : 360°
double& Quadrilatere::mCorrectionAngle(double&
pAngle)
{
// Corriger les dépassements
double vAngleMaximal = 360.0;
pAngle %= vAngleMaximal;
// Si l'angle est
if(pAngle < 0)
{
// Corriger le signe.
pAngle *= -1;
}
return pAngle;
}

// Propriété AngleA de Quadrilatere. Remarquez


comment la propriété contraint l'intégrité des
données de la classe via la méthode
mCorrectionAngle.
void Quadrilatere::mAngleA(double& pAngle):
Figure()
{
// Mettre à jour l'angle.
this->aAngleA = mCorrectionAngle(pAngle);
}

void Quadrilatere::mAngleB(double& pAngle)


{
// Mettre à jour l'angle.
this->aAngleB = mCorrectionAngle(pAngle);
}

void Quadrilatere::mAngleC(double& pAngle)


{
// Mettre à jour l'angle.
this->aAngleC = mCorrectionAngle(pAngle);
}

void Quadrilatere::mAngleD(double& pAngle)


{
// Mettre à jour l'angle.
this->aAngleD = mCorrectionAngle(pAngle);
}

// Une arrête n’est pas négative


double& Quadrilatere::mCorrectionArrete(double&
pArrete)
{
if(pArrete < 0)
{
pArrete *= -1;
}
return pArrete;
}

void Quadrilatere::mArreteAB(double& pArrete)


{
this->aArreteAB = mCorrigeArrette(pArrete);
}
void Quadrilatere::mArreteBC(double& pArrete)
{
this->aArreteBC = mCorrigeArrette(pArrete);
}

void Quadrilatere::mArreteCD(double& pArrete)


{
this->aArreteCD = mCorrigeArrette(pArrete);
}

void Quadrilatere::mArreteDA(double& pArrete)


{
this->aArreteCD = mCorrigeArrette(pArrete);
}

Quadrilatere::Quadrilatere(double& pArreteAB,
double& pArreteBC, double& pArreteCD, double&
pArreteDA, double& pAngleA, double& pAngleB,
double& pAngleC, double& pAngleD)
{
// Assure l'intégrité de la classe;
this->mArreteAB(pArreteAB);
this->mArreteBC(pArreteBC);
this->mArreteCD(pArreteCD);
this->mArreteDA(pArreteAD);
this->mAngleA(pAngleA);
this->mAngleB(pAngleB);
this->mAngleC(pAngleC);
this->mAngleD(pAngleD);
}

Quadrilatere::~Quadrilatere()
{
// rien à détruire.
}

void Quadrilatere::mDessine()
{
//Dessine ici le parallélogramme (vrais code
de dessin non pertinent car trop volumineux pour
le gain obtenu sur l’intérêt de la leçon).
cout << "Dessine Quadrilatere :\n" <<
"\tAB = " << this->mArreteAB() <<
",\n" <<
"\tBC = " << this->mArreteBC() <<
",\n" <<
"\tCD = " << this->mArreteCD() <<
",\n" <<
"\tDA = " << this->mArreteDA() <<
",\n" <<
"\tAngle A = " << this->mAngleA() <<
",\n" <<
"\tAngle B = " << this->mAngleB() <<
",\n" <<
"\tAngle C = " << this->mAngleC() <<
",\n" <<
"\tAngle D = " << this->mAngleD() <<
endl;
}
double Quadrilatere::mArreteAB()
{
return this->aArreteAB;
}

double Quadrilatere::mArreteBC()
{
return this->aArreteBC;
}

double Quadrilatere::mArreteCD()
{
return this->aArreteCD;
}

double Quadrilatere::mArreteDA()
{
return this->aArreteDAB;
}
double Quadrilatere::mAngleA()
{
return this->aAngleA;
}

double Quadrilatere::mAngleB()
{
return this->aAngleB;
}

double Quadrilatere::mAngleC()
{
return this->aAngleC;
}

double Quadrilatere::mAngleD()
{
return this->aAngleD;
}
dans "Figure.h"

#ifndef Figure_H
#define Figure_H

class Figure
{
public:
Figure();
virtual ~Figure();
virtual void mDessine() = 0; // "virtual
void mDessine() = 0;" est une méthode dite
"virtuelle pure" (à cause du "= 0").
// Elle n'a
pas de corps et rend donc de fait la classe
"Figure" abstraite. Cela signifie
// que l’on
ne peux pas instancier cette classe directement
Pour pouvoir instancier cette
// classe
il faut la dériver et implémenter la méthode
(lui donner un corps).
};

dans "Figure.cpp"

#include "Figure.h"

Figure::Figure()
{
}

Figure::~Figure()
{
}

// Le corps de mDessine n'apparait pas car c’est


une méthode virtuelle pure
Récupérée de « https://fr.wikiversity.org/w/index.php?
title=Langage_C%2B%2B/Classe&oldid=812194 »

Wikiversité

La dernière modification de cette page a été faite le 27 juin 2020 à 16:25. •


Le contenu est disponible sous licence CC BY-SA 3.0 sauf mention contraire.

Vous aimerez peut-être aussi