Programmation C++/Les classes
La notion de classe en programmation orientée objet.
Une classe permet de regrouper dans une même entité des données et des fonctions membres (appelées aussi méthodes) permettant de manipuler ces données. La classe est la notion de base de la programmation orientée objet. Il s'agit en fait d'une évolution de la notion de structure, qui apporte de nouvelles notions orientées objet absolument fondamentales. Un objet est un élément d'une certaine classe : on parle de l'instance d'une classe.
L'encapsulation en C++.
L'encapsulation est un mécanisme qui interdit d'accéder à certaines données depuis l'extérieur de la classe. Ainsi, un utilisateur de la classe ne pourra pas accéder à tous les éléments de celles-ci. Il sera obligé d'utiliser certaines fonctions membres de la classe (celles qui sont publiques). L'avantage de cette restriction est qu'il empêche par exemple un utilisateur de la classe de mettre les données dans un état incohérent. Vue de l'extérieur, la classe apparaît comme une boîte noire, qui a un certain comportement à laquelle on ne peut accéder que par les méthodes publiques. Cette notion est extrêmement puissante et permet d'éviter de nombreux effets de bord.
L'encapsulation permet de distinguer très nettement ce que fait la classe et sa sémantique précise, de la manière dont on l'implémente. Cette réflexion permet de répondre dans un premier temps à la question "Comment utilise-t-on la classe ?" Ce n'est que dans un second temps que l'aspect technique entre en jeu et que le programmeur doit répondre à la question "Comment vais-je programmer les fonctionnalités de la classe qui ont été spécifiées ?" L'encapsulation permet de faire abstraction du fonctionnement interne (c'est-à-dire, l'implémentation) d'une classe et ainsi de ne se préoccuper que des services rendus par celle-ci. 
Le C++ implémente l'encapsulation en permettant de déclarer les membres d'une classe avec l'un des mots réservés codice_1, codice_2 et codice_3. Ainsi, lorsqu'un membre est déclaré:
Le C++ n'impose pas l'encapsulation des membres dans leurs classes. On pourrait donc déclarer tous les membres publiques, mais en perdant une partie des bénéfices apportés par la programmation orientée objet. Il est de bon usage de déclarer toutes les données privées, ou au moins protégées, et de rendre publiques les méthodes agissant sur ces données. Ceci permet de cacher les détails de l'implémentation de la classe.
Les fonctions membres.
Parmi les fonctions membres, on distingue :
Déclaration.
La déclaration d'une fonction membre se fait de la même manière qu'une fonction régulière mais au sein de la portée de la classe. En outre, on pourra la suffixer du mot clé "const" pour signifier qu'il s'agit d'un accesseur.
class A
public:
 int getValue() const;
 void setValue(int value);
private:
 int value;
Définition.
Dans le cas d'une définition au sein de la classe même, elle est faite comme une fonction régulière. Dans ce cas, la fonction membre est automatiquement considérée comme "inline".
Dans le cas d'une définition en dehors de la classe, il faudra préfixer le nom de la fonction membre par le nom de la classe suivi de l'opérateur de portée (::). Dans ce cas, elle est automatiquement considérée comme non "inline".
class A
public:
 int getValue() const { return this->value; } // définition au sein de la classe
 void setValue(int value);
 void print() const;
private:
 int value;
inline void A::setValue(int value) // définition au sein de la classe (inline)
 this->value = value;
void A::print() const // définition en dehors de la classe (non inline)
 std::cout « "Value=" « this->value « std::endl;
En règle générale, les fonctions membres non "inline" devront être déclarées dans le fichier source .cpp de la classe, pour éviter d'avoir plusieurs fois la même définition au moment de l'édition des liens, et les fonctions membres "inline" devront être déclarées dans le fichier d'entête .hpp de la classe, pour permettre au compilateur de générer le code à chaque appel de la fonction.
Constructeurs et destructeur.
Les constructeurs et destructeur d'une classe sont des fonctions membres particulières de cette classe.
Destructeur.
Le destructeur d'une classe est appelé lorsqu'une de ses instances doit être détruite. Cela arrive à la fin de l'exécution d'une fonction/méthode lors d'une allocation dynamique : si vous avez déclaré, localement à une fonction/méthode, un élément d'une classe A par "A toto;" alors à la fin de l'exécution de la fonction/méthode, le destructeur de la classe est appelé automatiquement. Il est également appelé lorsqu'on détruit une instance avec codice_6.
Il ne peut y avoir qu'un seul destructeur pour une même classe. S'il n'est pas explicitement présent dans la classe, il sera généré par le compilateur. La syntaxe est similaire à celle du constructeur, à ceci près que le destructeur est introduit par un tilde et qu'il ne reçoit aucun argument :
codice_7
Un appel explicite avec codice_6 est nécessaire lorsqu'une instance a été allouée avec codice_5. Dans le cas contraire, si le pointeur est détruit sans appeler le destructeur, l'instance ne sera pas réellement supprimée et persistera en mémoire mais sans être accessible, ce qui occasionnera ce qu'on appelle une fuite de mémoire.
Exemples de classes.
Dans cet exemple de classe, les fichiers Point.h, Point.cpp et main.cpp vont vous être exposés. Tout d'abord, Point.h:
using namespace std;
class Point
public:
 // Constructeurs
 Point();
 Point(double x, double y);
 //Accesseurs et mutateurs
 void setX(double x);
 void setY(double y);
 double getX() const;
 double getY() const;
 // Autres méthodes
 double distance(const Point &P) const;
 Point milieu(const Point &P) const;
 void saisir();
 void afficher() const;
private: 
 double x,y;
Voici le fichier Point.cpp:
using namespace std;
Point::Point() : x(0), y(0)
Point::Point(double x, double y) : x(x), y(y)
void Point::setX(double x)
 this->x = x;
void Point::setY(double y)
 this->y = y;
double Point::getX() const
 return this->x;
double Point::getY() const
 return this->y;
double Point::distance(const Point &P) const
 double dx = this->x - P.x;
 double dy = this->y - P.y;
 return sqrt(dx*dx + dy*dy); 
Point Point::milieu(const Point &P) const
 Point result;
 result.x = (P.x + this->x) / 2;
 result.y = (P.y + this->y) / 2;
 return result;
void Point::saisir()
 cout « "Tapez l'abscisse : "; cin » this->x;
 cout « "Tapez l'ordonnée : "; cin » this->y;
void Point::afficher() const
 cout « "L'abscisse vaut " « this->x « endl;
 cout « "L'ordonnée vaut " « this->y « endl;
Et le fichier principal main.cpp:
using namespace std;
int main() 
 Point A, B, C;
 double d;
 cout « "SAISIE DU POINT A" « endl;
 A.saisir();
 cout « endl;
 cout « "SAISIE DU POINT B" « endl;
 B.saisir();
 cout « endl;
 C = A.milieu(B);
 d = A.distance(B);
 cout « "MILIEU DE AB" « endl;
 C.afficher();
 cout « endl;
 cout « "La distance AB vaut : " « d « endl;
 return 0;
Les opérateurs new et delete.
Il est parfois intéressant de créer dynamiquement de nouvelles instances d'une classe. Cela s'avère indispensable lorsque vous manipulez certaines structures de données complexes. L'opérateur codice_5 permet de créer une nouvelle instance d'une classe codice_11 en écrivant :
 A* pointeur=new A; // Ou bien:
 A* pointeur=new A();
Si le constructeur de la classe A prend des arguments, la syntaxe devient:
 A* pointeur=new A("arguments");
La variable codice_12 doit alors être du type codice_13.
La libération se fait en utilisant l'opérateur codice_6 et le destructeur de la classe est appelé:
 delete pointeur;
Surcharge d'opérateurs.
Présentation.
Pour certaines classes, la notion d'addition ou de multiplication est totalement naturelle. La surcharge d'opérateurs permet d'écrire directement "U+V" lorsqu'on veut additionner deux instances U et V d'une même classe A.
Syntaxe.
Les opérateurs unaires doivent être surchargés en tant que méthode de la classe.
La signature générique au sein de la classe est
où "@" est l'opérateur à surcharger: + - * / ...
Excepté pour certains d'entre eux, les opérateurs binaires peuvent être surchargés en tant que méthode de la classe ou comme une fonction à 2 arguments.
La signature générique est la suivante
où "@" est l'opérateur à surcharger: + - * / ...
Pour surcharger l'opérateur+ de la classe A, il suffit de créer une méthode:
ou encore une fonction externe à la classe:
Exemple.
using namespace std;
class Fraction
 friend ostream & operator«(ostream & out, const Fraction &f);
 friend istream & operator»(istream &in, Fraction &f); 
 public:
 Fraction();
 Fraction(int i);
 Fraction(int num, int den);
 Fraction operator+(const Fraction & f) const;
 Fraction operator-(const Fraction & f) const;
 Fraction operator*(const Fraction & f) const;
 Fraction operator/(const Fraction & f) const;
 private:
 int num,den; 
 static int pgcd(int x, int y);
 void normalise();
Fraction::Fraction() : num(0), den(1)
Fraction::Fraction(int i) : num(i), den(1)
Fraction::Fraction(int num, int den) : num(num), den(den)
 normalise();
ostream & operator«(ostream &out, const Fraction &f)
 if (f.den != 1)
 out « f.num « "/" « f.den;
 else
 out « f.num;
 return out;
istream & operator»(istream &in, Fraction &f)
 string s;
 bool ok = true;
 do
 cout « "Tapez le numerateur : "; getline(in, s);
 istringstream is1(s);
 ok = (is1 » f.num) && is1.eof();
 } while(!ok);
 do
 cout « "Tapez le denominateur : "; getline(in, s);
 istringstream is2(s);
 ok = (is2 » f.den) && is2.eof();
 } while(!ok);
 f.normalise();
 return in;