« Langage C++/Classe » : différence entre les versions

Contenu supprimé Contenu ajouté
Page créée avec « == La Classe == En programmation orienté objet, tout est basé sur le concept de la classe. La classe est une entité autonome capable de maintenir une fois instanciée la … »
(Aucune différence)

Version du 8 mai 2009 à 23:41

La Classe

En programmation orienté objet, tout est basé sur le concept de la classe. La classe est une entité autonome capable de maintenir une fois instanciée 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 tiers 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és. (Normalement uniquement utilisé pour les méthodes)
  • Public : Permet de partager les données avec toutes les classes tiers. (Normalement uniquement utilisé pour les méthodes)


Les Attributs : Variable de classes

La classe est une entité qui peut être composé de variables internes que l'on nome attributs membre.

La théorie veut que les attributs d'une classe ne soient accessibles directement qu'à cette classe. Bien qu'en C++ il est possible de définir des attributs membres de visibilité publique ou protégés, il est normalement indispensable de rendre les attributs membres privés (je n'ai jamais eu à rendre publique ou même protégé des attributs hormis pour des classes-énumérations que nous verrons plus tard).

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 serais 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 aurais besoins 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é 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 :

  • Carre
  • Rectangle
  • Parallélogramme
  • Losange
  • Quadrilatere
  • Cercle
  • Ovale

Imaginons maintenant que nous devions réaliser des classes basé sur ces figures. Supposons que chaque classe doit être capable de 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 déssin de toutes les classes.

Dans les figure imposés on peut voir que "Carre" 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 "Quadrilatere". Quant à "Losange" c'est un "Quadrilatere"

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

Cependant rien ne lie Ovale et Quadrilatere.

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 Puisqu'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 soient dotés.


Abstraction de classes

Lors de généralisations successives il est courent de se rendre compte qu'une classe est trop "abstraite" pour avoir suffisamment de données exploitable 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 fournis une interface que toutes les autres classes devront reproduire fidèlement. La méthode "Déssiner" ne représente pas grand choses 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'aurais 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é non abstraite peut être interprété 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és 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é 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 ces membres de la classe ancêtre la théorie objet veux que l'on hérite toujours des classes ancêtre de manière publique affin que tous les membres public de la classe ancêtre soient aussi disponibles de manière publique dans la classe dérivé. L'héritage permet de ne pas réécrire eternellement les mêmes codes, de réutiliser les objets, de pouvoir en spécialisermettre en œuvre le polymorphisme.


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é 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 vas appeler la méthode virtuelle et par le biais de l'héritage virtuel appeler la méthode implémenté dans la classe Carré.

Implémentation

Les classes sont donc la représentation physique du concept d'objet. Voici en C++ comment implémenter ces classe conformément à la théorie de l'objet.


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 methodes 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és 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 Macro), soit définies en dehors de la déclaration dans un fichier source séparé de la manière suivante:


Voici un exemple de la classe la plus simple à réaliser. Il faut dire aussi qu'elle ne fait strictement rien.

Début de l'exemple
Fin de l'exemple


Exemples:

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

Début de l'exemple
Fin de l'exemple