La notion de classe, d'attributs, de méthodes et de constructeurs
En programmation objet, une classe déclare (définit) des
propriétés communes à un ensemble d'objets
(les instances de la
classe). C'est un "moule" à partir duquel on crée des objets.
Une classe est en quelque sorte une autre forme de types.
Que contient une déclaration de classes?
Elle contient :
des déclaration de données - variables (en programmation
objet, on les appelle des attributs) ; il s'agit ici d'attributs de
classe par opposition au concept d'attributs d'instance ;
et des déclaration de fonctions (en
programmation objet, on les appelle des méthodes).
La syntaxe dit simplement qu'une classe (En Python, on parle
d'objet classe), c'est un nom (Compte-chèque dans l'exemple
ci-dessous) et est une suite d'instructions. Notez
que le nom d'une classe commence par une majuscule. Ce n'est pas
obligatoire ; mais cela permet de les distinguer des noms
d'instances et autres
objets.
Des méthodes particulières, les constructeurs,
permettent de construire les objets, instances de la
classe. Les constructeurs ont
un nom particulier __init__ en python
(notez que init est entouré des deux côtés par deux caractères
soulignés). Notez aussi que _init_ apparait 2 fois, une fois sans
paramètres (le
compte est initialisée à 0) et une fois avec un paramètre. Il y a
surcharge
(overloading de la fonction _init_). 2
fonctions avec le
même nom. L’ambiguïté est levée à l'appel de la fonction.
Un attribut d'instance
existe en autant d'exemplaires qu'il y a d'instances créés
d'une même classe. Le seul fait d'écrire self.sommeEnDepot =
0 dans la première fonction _init_
introduit (déclare) un attribut
d'instance. Notez la notation pointée. Il ne faut pas oublier
self., car il se
pourrait que dans une autre portée (classe,
...) existe un autre sommeEnDepot
On accède directement de l'intérieur de la classe,
sans notation pointée, aux attributs de la classe.
De l'extérieur de la classe, on utilise la notation pointée.
Les classes peuvent être reliées par un lien d'héritage qui
traduit une relation "est un" entre les objets, ainsi qu'une
hiérarchie du plus abstrait au plus concret, du plus général au
plus spécialisé.
Un humain est un mammifère. Et un mammifère est un animal. Un
animal est un être vivant.
class etreVivant :
# attributs des êtres vivants
class animal (etreVivant) : # animal est est une sous-classe de
etre Vivant. etreVivant est une sur-classe de animal
# attributs spécifiques aux instances de
animal. Certains attributs de animal peuvent être redéfinis à
ce niveau (cf redéfinition)
class mammifere (animal)
# attributs spécifiques aux instances de
mammifere
class humain (mammifere)
# attributs spécifiques aux instances de
mammifere
Nous avons ci-dessus des cas d'héritage simple.
Une classe hérite d'une seule classe et pas de plusieurs.
Puis d'accéder aux attributs de ces objets, par la notation
pointée habituelle :
a.ageEstimee ()
h.ageEstimee ()
Pour chaque classe, un fonction ageEstimee
est fournie avec différents
algorithmes (redéfinition). Un humain est un animal, mais quand
on sait aiguiller vers le bon algorithme.
Un doctorant est membre du personnel. Il est aussi élève. Et les
membres du personnel et les élèves sont des humains.
class membreDuPersonnel (humain)
# attributs nouveaux et redéfinitions d'attributs
class eleve (humain)
# attributs nouveaux et redéfinitions d'attributs
class doctorant (membreDuPersonnel, eleve)
# attributs nouveaux et redéfinitions d'attributs
doctorant est à la fois une sous-classe directe des classes
membreDuPersonnel et eleve. Il y a héritage
multiple.
Attention, un conflit peut apparaitre si un attribut n'est
pas défini dans une classe (doctorant), mais dans chacune des
classes mères (membreDuPersonnel et eleve). Et bien Python
s'évite les complications. Il regarde d'abord si l'attribut est
dans membre du Personnel, puis s'il n'est pas dans eleve, puis
s'il n'est pas dans humain, puis ... Il ya un ordre de résolution
de conflit d'héritage.
Dans le cas général. Profondeur d'abord, puis de gauche à
droite.For most purposes,
in the simplest cases, you can think of the search for attributes
inherited from a parent class as depth-first, left-to-right, not
searching twice in the same class where there is an overlap in
the hierarchy. Thus, if an attribute is not found in DerivedClassName, it is searched for in Base1, then (recursively) in the base classes
of Base1, and if it was not found there, it was
searched for in Base2, and so on.