Classes & Objets


Préambule d'approche

Vous connaissez les concepts de variable et de fonction.
Nous allons vous faire découvrir un nouveau concept fait à la fois de variables et de fonctions.
C'est l' objet.
Nous allons donner un exemple :
Il existe un objet assez courant appelé "chaîne de carcatères" - String -
On le déclare comme ceci :

s = new String("Ah que je suis content !");

Mais on a plus l'habitude de le voir déclarer sous la forme :

s = "Ah que je suis content !";


Nous verrons plus tard la subtile différence entre les deux déclarations.

Cet objet cache en son sein à la fois :

  • des fonctions, que nous allons desormais appeler "méthodes"
  • est des variables que nous allons desormais appeler "propriétés"

Exemple : Déclenchez les alertes correspondant à chaque ligne en cliquant sur les : :

s = "Ah que je suis content !";
alert(s.length);
alert(s.charAt(7));

  • s.lenght donne la longueur (nombre de caractères) de la chaîne.
    s.length est une propriété de l'objet chaîne s.
  • s.charAt(7) retourne le caractère d'index 7 de la chaîne (ici le 'j' )
    s.charAt(7) est une méthode de l'objet chaîne s.

Fin du préambule

1 Objectifs
Créer des concepts qui rendent la programmation plus simple, aisée et plus sûre même lorsque la complexité des problèmes augmente considérablement.

2 Concept de classe et d'objet
La programmation orientée objet manipule ce que l'on appelle des " objets " à travers la notion de " classe ".
Il existe la même différence entre "classe " et " objet " qu'entre type et variable.

Exemple :
double i ;
est la déclaration de la variable "i" de type " double ".

Une variable occupe de la place en mémoire.
Un type comme "double " n'en occupe pas, c'est un concept descriptif qui a certaines implications pour "i" que vous connaissez.

Un " objet " a une réelle existence en mémoire (il ressemble beaucoup à une variable).
Une " classe " n'a pas d'existence en mémoire mais ce concept nous permettra de définir l'objet, tout comme le fait un " type " pour une variable.

Il y a donc une certaine ressemblance en " classe " et " type ". Le concept de classe est toutefois incomparablement plus puissant comme nous allons voir.

Voici par exemple la définition d'une classe que nous appellerons " CChaine ".

// chaine.h

class CChaine
{
// Constructeurs & destructeurs
public:

CChaine();
~CChaine();
CChaine(char * pChaine);

// Implementation
public:

int NbCaracteres(); //Fonction membre - Méthode
void GardeEspacesUtiles(); //Fonction membre - Méthode
void ConvertToMaj(); //Fonction membre - Méthode
void OteEspaces(); //Fonction membre - Méthode
char Caractere(int Index); //Fonction membre - Méthode
bool ContientMot(char* pMot); //Fonction membre - Méthode

// Attributs
private:

int m_nbCar; //Attribut
char * m_pChaine; //Attribut
};

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Il s'agit ici de chaînes de caractères.
Un objet mettons " Phrase " de la classe CChaine peut être déclaré de la manière suivante :

CChaine Phrase ;

Dès lors, cet objet " Phrase " est opérationnel en mémoire. Il comporte des fonctions dites " Fonctions membres " telles que " GardeEspacesUtiles() " dont le lecteur devine assez aisément la fonction.
Il comprend également des variables telles que " m_nbCar " dont on devine également qu'elle désigne le nombre de caractères de l' " objet chaîne " ainsi déclaré.


3 Constructeurs - destructeurs

On remarquera l'existence des fonctions : " Cchaine( ) " " CChaine(char* pChaine) " dites " Constructrices "
On les appelle aussi " Constructeurs "

// chaine.h

class CChaine
{
// Constructeurs & destructeurs
public:

CChaine();
~CChaine();
CChaine(char * pChaine);
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Ces fonctions sont indispensables pour que le logiciel de compilation puisse réserver de l'espace mémoire et rendre opérationnels les objets déclarés par la classe.

Par exemple, si on veut déclarer une chaîne vide on écrira

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
CChaine Chaine ; //Appel au premier constructeur
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Pour une chaîne contenant le texte " Salut ! " on fera appel au second constructeur :*

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
CChaine Chaine(" Salut ! ") ; //Appel au second constructeur
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Vous remarquez également la fonction : " ~CChaine() " appelée " destructeur " : le signe " tilde ~" précédant le nom de classe est la marque de tout destructeur d'objet.

Cette fonction est appelée lorsque l'objet n'est plus utilisé pour libérer la mémoire système.
Le programmeur doit généralement écrire lui-même les diverses libérations de mémoire à effectuer.
Sauf si aucune réservation n'a été faite implicitement dans les fonctions membres de la classe.

4 Fonctions membres

Une fonction membre réalise une ou des opérations sur l'objet.

Exemple :

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
//Déclaration de l'objet " Phrase "
CChaine Phrase(" Oh Zénon, cruel, Zénon, Zénon d'Elée ") ;

//Utilisation de l'objet " Phrase "
Phrase.GardeEspacesUtiles() ; //Enlève les espaces inutiles de la phrase
Phrase.ConvertToMaj() ; //Convertit tout en majuscules
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

On comprend avec cet exemple la facilité d'écriture et mnémotechnique des classes qui s'apparente à l'utilisation des structures. Les notions de classe et de structure sont pratiquement confondues en C++.

5 Attributs
A côté des fonctions membres on trouve les attributs attachés à la classe qui s'apparentent à des variables.
Ces attributs ne sont autres que des variables stockées en mémoire et étroitement liées à la classe.
Le nombre de caractères d'une chaîne, par exemple, répond à ces critères.

// chaine.h

class CChaine
{
// Constructeurs & destructeurs
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int m_nbCar; //Attribut
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Dans l'objet " Phrase " précédent, on peut désigner cet attribut par / " Phrase.m_nbCar "
Encore une fois, l'analogie avec les structures est patente.


Privés et publics " private " & " public "

Vous observez les mots réservés " private : " et " public : " précédant, dans la déclaration de classe, la déclaration de certaines fonctions membres ou attributs.

Une fonction membre privée d'un objet ne peut pas être appelée par l'utilisateur de cet objet.
Elle ne peut l'être que par le programmeur qui a réalisé la classe.

Un attribut privé d'un objet ne peut être ni modifié ni utilisé par l'utilisateur de cet objet.
Il ne peut l'être que par le programmeur qui a réalisé la classe.

En fait, l'utilisateur d'une classe, d'un objet, n'a même pas à avoir connaissance des procédures ou des attributs privés.

L'utilité d'une telle distinction entre privé et public est qu'elle empêche l'utilisateur d'un objet de manipuler les éléments de cet objet qui exigent une connaissance approfondie du fonctionnement interne de cet objet.

Pour utiliser une métaphore, nous dirons qu'il est bon que le conducteur d'une automobile n'ait pas à entrer dans tous les détails de la conception mécanique interne du véhicule pour le piloter convenablement et en assurer la sécurité. N'empêche que ces détails sont indispensables et accessibles aux concepteurs du véhicule.

La conséquence à noter par les concepteurs d'objets est qu'ils devront faire en sorte qu'une fonction membre ou un attribut publics, ne fassent jamais appel à quelque connaissance de la structure interne de la classe par ses futurs utilisateurs.

6 Exercices d'entraînement

Créer un nouvel espace de travail que l'on appellera " objets ".
Dans cet espace, on créera un nouveau projet appelé " premierobjet "

· Nous affichons ci-dessous les deux fichiers " chaine.h " et " chaine.cpp " définissant une classe que nous appelons " CChaine " et que nous avons laissée très incomplète.
· Le fichier " objet_1.cpp " contient un programme principal appelant cet objet.

Nous vous conseillons de lire attentivement le cours qui précède et d'essayer d'écrire vous-même des fichiers équivalents, de compiler le projet, de le lancer. Le copié-collé des fichiers ci-dessus ne vous apprendra pas à créer des programmes de manière autonome.

Un pis aller consiste à :

· Relever par copié-collé ces fichiers, compiler le projet entier, se rendre compte de la façon dont il fonctionne.

Au delà de ce premier contact :
· Complétez les procédures qui ne sont pas développées
· Enrichissez la classe CChaine.par des procédures à vous.

// chaine.h

class CChaine
{
// Constructeurs & destructeurs
public:
CChaine(); //Constructeur
CChaine(char * pChaine); //Constructeur
~CChaine(); //Destructeur

// Implementation
public:
int NbCaracteres(); //Fonction membre - Méthode
void OteEspaces(); //Fonction membre - Méthode
void GardeEspacesUtiles(); //Fonction membre - Méthode
void ConvertToMaj(); //Fonction membre - Méthode
char Caractere(int Index); //Fonction membre - Méthode
bool ContientMot(char* pMot); //Fonction membre - Méthode
bool ContientMot(CChaine &C); //Fonction membre - Méthode
void Vider(); //Fonction membre - Méthode

//Attributs
private:
int m_nbCar; //Attribut
char * m_pChaine; //Attribut
};

Fichier " chaine.cpp " en page suivante

// chaine.cpp

#include "chaine.h"

//Constructeur d'une chaîne vide
CChaine::CChaine()
{
m_pChaine = new char[1];
*m_pChaine = 0; //Terminateur
}

//Constructeur à partir d'une chaîne classique
CChaine::CChaine(char* pChaine)
{ //Compte le nb de caractères
for(m_nbCar = 0; pChaine[m_nbCar] ;m_nbCar++) ;
m_pChaine = new char[m_nbCar +1]; // "+ 1" = Place pour le terminateur
//On place la chaîne dans la mémoire interne de l'objet
for(m_nbCar = 0; m_pChaine[m_nbCar] = pChaine[m_nbCar] ;m_nbCar++) ;}

//Destructeur
CChaine::~CChaine(){ delete[] m_pChaine;}

//Retourne le caractère ayant pour index " Index "
char CChaine::Caractere(int Index)
{
if(Index < m_nbCar) return m_pChaine[Index];
else return 0;
}

CChaine::NbCaracteres(){ return m_nbCar; }


//Procédures à réaliser et tester

void CChaine::ConvertToMaj(){}

void CChaine::GardeEspacesUtiles(){}

void CChaine::OteEspaces(){}

bool CChaine::ContientMot(char* pMot){ return true; }

bool CChaine::ContientMot(CChaine &C){ return true;}

void CChaine::Vider(){}


#include "chaine.h"
#include <stdio.h>

void main()
{
char * pCh ="Salut les gars !";

CChaine Chaine(pCh);

printf("Nombre de caratères de la chaîne : %i\n", Chaine.NbCaracteres());

printf("Le second caractère de la chaîne est : %c\n", Chaine.Caractere(1));

char c; int i=0;
do
putchar(c=Chaine.Caractere(i++)); //putchar(c) <stdio.h> affiche caractère
while(c);
putchar('\n');

}