IV.ANNEXES:
AVERTISSEMENT:
Ce dernier chapitre regroupe des notions qui ne sont généralement pas traitées dans le
cadre de l'algorithmique, mais qui ont pourtant une grande importance dans les langages de programmation
(notion d'évènement, parallélisme, notiond'objets). Il nous est apparu intéressant
de les traiter ici, indépendamment de tout langage de programmation, de façon à faire
ressortir les aspects fondamentaux de leur problématique.
D'autre part, les notions qui apparaîssent dans ce chapitre ne font l'objet d'aucune convention
d'écriture en algorithmique. De ce fait, des solutions sont proposées pour les noter.
IV.1.ANNEXE I: GESTION D'EVENEMENTS:
IV.1.1.LA NOTION DE FLOT DE CONTRÔLE:
IV.1.1.1.DEFINITION:
En algorithmique, on considère qu'à un instant donné, un processeur peut exécuter
un algorithme et un seul. D'autre part, nous avons vu que l'ordre dans lequel un processeur exécute
les instructions d'un algorithme était déterminé par:
- L'ordre défini par la liste d'instructions, lorsqu'il exécute une structure
séquencielle.
-
- L'état de l'environnement d'exécution, lorsqu'il exécute une structures
alternatives ou itérative.
Nous verrons plus loin que d'autres causes sont susceptible d'intervenir.
La suite des instructions parcourues par le processeur peut donc varier d'une exécution à
l'autre, en fonction de la réalisation ou non de telle ou telle condition. En particulier,
le nombre de répétitions des instructions incluses dans des structures itératives peut
varier.
DEFINITION:
La suite des instructions parcourues par un processeur lors de l'exécution d'un algorithme est
appelée FLOT DE CONTRÔLE.
REMARQUE:
Le flot de contrôle est intuitivement assimilable à la «trace» que laisserait le
processus en parcourant les instructions de l'algorithme, ou bien à un «fil d'Ariane»
(en anglais, filin = «thread» ...) qu'il suivrait, et sur lequel seraient «fixées» les instructions
qu'il exécute.
IV.1.1.2.FLOT DE CONTRÔLE D'UN ALGORITHME ISOLE DE TOUTE INFLUENCE:
En l'absence de toute influence externe à l'algorithme (et en particulier en l'absence d'instruction
d'entrée), le flot de contrôle ne dépend que de l'ordre de la liste des instructions de
cet algorithme et de l'état de son espace d'exécution au moment de
l'exécution de chaque instruction conditionnelle (alternative ou itérative).
DEFINITION: On appelle «état de l'espace d'exécution» à un
instant donné l'ensemble des valeurs des contenus des variables de l'espace d'exécution à
cet instant.
Dans le cas d'un algorithme isolé, l'état En de l'espace
d'exécution après la nieme instruction ne dépend que de l'état
En-1 de cet espace avant l'exécution de cette instruction et de
la nature de cette nieme instruction. On peut en déduire par récurrence que
dans le cas d'un tel algorithme, le flot de contrôle est entièrement prédictible
à partir de l'état initial E0 de l'espace
d'exécution.
EXEMPLE:
00 DEBUT
01 // Déclaration des données (Espace d'exécution)
02 var A en numerique
03 var B en numerique
04 var R en numerique
05 // Debut procedure
06 A←3
07 B&larr - 2
08 R← A – B
09 SI R < 0 ALORS
10 SORTIR "A est plus petit que B" // Sur l'écran
11 SINON
12 SORTIR "A est plus grand ou égal à B" // Sur l'écran
13 FINSI
14 FIN
Cet algorithme n'inclue aucune opération d'entrée. Le flux de contrôle ne dépend
donc que de l'état initial de son espace d'exécution:
- Ici, cet état est initialisé à A = 3 et B = -2. De ce fait, le flot de
contrôle suivra les instructions 5, 6, 7, 8, 9, 12, 13 et 14.
- Si l'on avait initialisé A et B à 3, le flot de contrôle serait: 5, 6, 7, 8,
9, 10, 11, 13 et 14.
IV.1.1.3.FLOT DE CONTRÔLE D'UN ALGORITHME NON ISOLE DE TOUTE INFLUENCE:
Une influence externe à l'algorithme peut avoir pour effet soit de modifier l'espace d'exécution
de l'algorithme, ce qui peut, par le jeux des instructions conditionnelles, amener une modification du flot
de contrôle, soit de perturber directement ce même flot de contrôle.
ALGORITHME COMPORTANT UNE INSTRUCTION ENTRER:
La modification de l'espace d'exécution par une influence externe peut être provoquée
tout simplement par une instruction ENTRER: dans l'exemple ci-dessus, la valeur de A pourrait être
saisie par une instruction ENTRER A au lieu d'être fixée par une affectation. Remarquons que la
présence d'une entrée implique l'existence d'un processeur extérieur: la personne ou
l'équipement qui fournit les informations d'entrée.
Dans ce cas, à condition que:
- L'instruction d'entrée puisse être atteinte par le flot de données à
partir de l'état initial.
- Les données acquises aient une influence sur le déroulement du flot de données
Le flot de données ne sera plus entièrement prédictible, puisqu'il dépendra en
partie de la valeur acquise.
ALGORITHME INTERAGISSANT PAR DONNEES PARTAGEES AVEC UN AUTRE ALGORITHME:
Il existe un autre cas ou l'on peut envisager la modification de l'espace d'exécution d'un
algorithme par une influence extérieure: c'est le cas de l'exécution simultanée
(par plusieurs processeurs) de plusieurs algorithmes se partageant le même espace d'exécution.
Ce type d'interaction est très souvent utilisé lorsque deux processus travaillant de manière
asynchrone l'un de l'autre doivent échanger des données:
EXEMPLE:
Une station de météorologie reçoit toutes les 5 secondes l'information «vitesse du
vent», mesurées par un anémomètre. Cette station de météorologie
doit fournir à des clients, lorsque ceux-ci le demandent, une des indications suivantes: «vent
faible», «vent moyen» ou «vent fort», en fonction de la vitesse du vent
calculée par une moyenne glissante. On peut modéliser ce système par deux algorithmes
asynchrones l'un de l'autre, s'exécutant en même temps. Le premier algorithme assure
l'acquisition de la vitesse du vent et calcule la moyenne glissante (celle-ci consiste ici à prendre
90% de la moyenne précédente et 10% de la valeur courante):
DEBUT
var VitesseVent en numerique
var VitesseMoyenne en numerique
VitesseMoyenne ← 0
TANT QUE ( <La station est en fonction> ) FAIRE
ENTRER VitesseVent // depuis le capteur de température
VitesseMoyenne ← ( VitesseMoyenne * 0,9 ) + ( VitesseVent * 0,1 )
FINFAIRE
FIN
Le deuxième algorithme assure la fourniture de la vitesse moyenne du vent quand un client la demande:
DEBUT
var VitesseMoyenne en numerique
var DemandeClient en chaîne de caractères
TANT QUE ( <La station est en fonction> ) FAIRE
ENTRER DemandeClient
SI DemandeClient = ''Vitesse Vent'' ALORS
SI VitesseMoyenne < 10 ALORS
SORTIR ''vent faible'' // Vers l'écran du client
SINON SI (VitesseMoyenne >= 10) ET < 30) ALORS
SORTIR ''vent moyen'' // Vers l'écran du client
SINON SI VitesseMoyenne > 30 )ALORS
SORTIR ''vent fort'' // Vers l'écran du client
FINSI
FINSI
FINFAIRE
FIN
On voit que le deuxième algorithme a besoin d'échanger la valeur courante de la donnée
VitesseMoyenne avec le premier. On pourrait envisager de faire communiquer les deux algorithmes par des
opérations d'entrée-sortie, mais cela impliquerait de trouver un point de synchronisation
entre les deux algorithmes ou de disposer d'entrées bufferisées.
Une solution plus simple consiste à rendre commune une partie des deux espaces d'exécution en
déclarant la donnée VitesseMoyenne «donnée partagée» entre les deux
algorithmes. On pourra représenter ce fonctionnement par les algorithmes suivants:
DONNEES PARTAGEES
var VitesseMoyenne en numerique
FIN DONNEES PARTAGEES
DEBUT
var VitesseVent en numerique
VitesseMoyenne ← 0
TANT QUE ( <La station est en fonction> ) FAIRE
ENTRER VitesseVent // depuis le capteur de température
VitesseMoyenne ← ( VitesseMoyenne * 0.9 ) + ( VitesseVent * 0,1 )
FINFAIRE
FIN
DEBUT
var DemandeClient en chaîne de caractères
TANT QUE ( <La station est en fonction> ) FAIRE
ENTRER DemandeClient
SI DemandeClient = ''Vitesse Vent'' ALORS
SI VitesseMoyenne < 10 ALORS
SORTIR ''vent faible'' // Vers l'écran du client
SI (VitesseMoyenne >= 10) ET(VitesseMoyenne < 30) ALORS
SORTIR ''vent moyen'' // Vers l'écran du client
SINON SI VitesseMoyenne > 30 )ALORS
SORTIR ''vent fort'' // Vers l'écran du client
FINSI
FINSI
FINSI
FINFAIRE
FIN
On voit que le flot de contrôle du deuxième processeur sera affecté par la valeur de la
variable VitesseMoyenne, qui elle-même dépendra de la valeur de la vitesse du vent saisie par
le premier algorithme.
REMARQUE:
Les deux algorithmes étant asynchrones, il est possible que parfois ils accèdent en même
temps à la donnée VitesseMoyenne. Dans une application informatique, la modification de cette
donnée par le premier processus n'est pas instantatée. Sa lecture simultanée par le
deuxième peut donc poser des problèmes (la lecture d'une donnée en cours de modification
peut aboutir à l'acquisition d'un état transitoire non significatif). Ces problèmes sont
résolus par des dispositifs appelés sémaphores. En algorithmique, on négligera
cet aspect..
ALGORITHMES TRAITANT DES EVENEMENTS:
Une autre cause de perturbation du flot de contrôle est la prise en compte d'événements.
Ce cas sera traité au paragraphe suivant.
IV.1.2.GESTION DES EVENEMENTS:
IV.1.2.1.EVENEMENTS ET SIGNAUX:
DEFINITION:
En informatique, un SIGNAL est un dispositif qui permet de prévenir un processeur de la survenue
d'un événement lié à des causes (externes ou internes au processeur), totalement
indépendantes du processus en cours d'exécution.
Par exemple, un signal peut prévenir un processeur qu'une touche du clavier a été
frappée ou qu'un bouton de la souris a été «cliqué»: la frappe peut
être totalement asynchrone du processus en cours. Mais un signal peut aussi être engendré
par une cause interne: par exemple, une anomalie de fonctionnement ou la fin d'un délai d'attente
programmé sur l'horloge interne.
Prévenir un processeur de la survenue d'un événement n'a pas grande utilité
si le processeur n'est pas capable de modifier son flot de contrôle immédiatement pour agir
en conséquence. De ce fait, les processeurs informatiques incluent plusieurs mécanismes
permettant de prendre en compte les signaux dès leur survenue. Ils peuvent se ranger en deux
catégories:
- Les instructions de mise en attente du processus
- Les mécanismes de traitement des interruptions.
IV.1.2.2.TRAITEMENT SYNCHRONE DES EVENEMENTS - MISE EN ATTENTE DU PROCESSEUR:
Cette technique repose sur l'emploi d'instructions dites «d'attente». Lorsque le processeur
rencontre une de ces instructions, il arrète le flot de contrôle sur celle-ci jusqu'à ce
qu'il ait reçu le ou les signaux que cette instruction est sensé attendre.
Dès qu'un des signaux attendus survient, le flot de contrôle redémarre en séquence.
DEFINITION:
Une INSTRUCTION D'ATTENTE a pour effet d'arrêter le flot de contrôle jusqu'à la
survenue d'un signal. Elle permet donc de synchroniser un flot de contrôle avec l'arrivée
de l'événement associé à ce signal.
NOTATION DES INSTRUCTIONS D'ATTENTE:
Les langages informatiques définissent toute une gamme d'instructions d'attente. Certaines sont
spécialisées (comme l'instruction delay du langage c sous windows, qui permet d'attendre la
survenue d'un signal de fin de décompte envoyé par l'horloge interne), d'autres sont
associées avec des structures de données permettant de définir quels signaux sont
attendus (par exemple l'instruction sigwaitinfo sous posix 4). En algorithmique, ces instructions pourraient
être notées:
ATTENDRE <signal 1> <signal 2> ... <signal n>
On peut aussi définir l'événement comme la fin d'un délais d'attente de n
secondes:
ATTENDRE 15 secondes
Dans tous les cas, pendant l'attente, le processeur est libéré. Il peut donc être
affecté à l'exécution d'un autre algorithme.
EXEMPLE:
On veut afficher sur un écran, toutes les secondes rondes, l'heure courante:
DEBUT
// Données locales
var HeureCourante en numerique
// Debut procedure
TANT QUE <on veut afficher la date > FAIRE
ATTENDRE <la seconde ronde>
ENTRER HeureCourante // DEPUIS l'horloge interne
SORTIR heureCourante // VERS l'écran
FIN TANT QUE
FIN
REMARQUE:
En algorithmique, une opération ENTRER se comporte implicitement comme une instruction:
ATTENDRE <information a entrer>
En effet: soit l'information est déjà présente au moment ou le processeur
l'exécute, et le flot de données continue, soit l'information n'est pas encore présente
et on attend l'événement d'arrivée de cette information.
IV.1.2.3.TRAITEMENT ASYNCHRONE DES EVENEMENTS - INTERRUPTIONS:
NOTION D'INTERRUPTION:
Les processeurs informatiques incorporent tous un mécanisme de «traitement d'interruptions»
dont voici la description schématique:
DEFINITION:
Le mécanisme d'interruption permet à un processeur d'interrompre provisoirement le flot de
données en cours pour aller exécuter un traitement plus urgent, lié à la survenue
d'un signal. Ce traitement est appelé souvent «gestionnaire d'interruption»:
Le principe de ce mécanisme est le suivant:
- Supposons que le processeur soit en train d'exécuter l'algorithme A1.
- Supposons alors qu'à un instant donné, pendant que le processeur exécute
l'instruction In de cet algorithme, un événement (signal)
survienne. Le mécanisme d'interruption déroute alors, à la fin de l'exécution
de In, le flot de contrôle vers un algorithme A2, qui dépend de
l'événement reçu. Simultanément, le contexte d'exécution de l'algorithme A1
est sauvegardé.
- Le processeur exécute alors l'algorithme A2 qui contient les traitements spécifiques
à cette interruption.
- A la fin de l'algorithme A2, le flot de contrôle est redirigé vers l'endroit oû
il a été interrompu dans l'algorithme A1, c'est à dire après l'instruction
In. Le contexte d'exécution sauvegardé à
l'étape 2 est remis en place.
ANALOGIE:
- Un employé administratif est à son bureau, en train de traiter à son rythme des
dossiers en attente (Algorithme A1)
- Le téléphone sonne.
- L'employé interromp le fil de son travail (son flot de contrôle) pour répondre au
téléphone. Ce faisant, il va essayer de sauver son contexte d'exécution (par exemple,
il va repérer la page du dossier qu'il est en train de consulter).
- Il va alors prendre en compte l'appel et essayer de satisfaire son interlocuteur, ce qui va l'amener
à effectuer un certain nombre d'actions sans rapport avec son activité courante (algorithme A2).
- Lorsqu'il aura terminé de traiter l'appel téléphonique, il reviendra à son
travail courant: pour cela, il rétablira son contexte d'exécution en réouvrant le
dossier en cours à la page dont le numéro a été
repéré.
REMARQUES:
- Lorsqu'un processeur accepte le traitement d'interruptions, le flot de contrôle peut devenir
totalement imprévisible. En effet, le gestionnaire d'interruptions peut modifier l'espace
d'exécution de l'algorithme A1 (par exemple en effectuant une instruction ENTRER).
- Un gestionnaire d'événement peut être lui-même interrompu par un
événement de priorité supérieure.
DEFINITION D'UN GESTIONNAIRE D'INTERRUPTION:
En algorithmique, on pourra définir un gestionnaire d'interruption par l'instruction suivante:
QUAND <signal> FAIRE <Nom de fonction>
EXEMPLE D'UTILISATION D'UN GESTIONNAIRE D'INTERRUPTIONS:
Supposons que sur un écran d'ordinateur, nous ayons ouvert deux fenêtres: dans la fenêtre
numéro 1, nous voulons éditer un texte, alors que dans la fenêtre numéro 2 nous
voulons afficher l'heure courante toutes les secondes, avec moins d'une seconde d'imprécision. Ce
fonctionnement pourrait être décrit de la manière suivante:
DEBUT
// Données locales:
var NomFichierTexte en chaine de caracteres
var CommandeTexte en chaine de caracteres
var TexteSelectionne en chaine de caractere
// Debut procedure Traitement_de_Texte:
<Affichage de l'éditeur de texte dans la fenêtre n° 1>
<Affichage de l'horloge dans la fenêtre n° 2>
QUAND <Signal seconde ronde> FAIRE AfficherDate
TANT QUE <on veut éditer le texte> FAIRE
ATTENDRE <Saisie d'une commande d'édition de texte>
ENTRER CommandeTexte // DEPUIS Fenêtre n° 1
SUIVANT LE CAS CommandeTexte FAIRE
CAS Ouvrir:
<Afficher la liste des fichiers du répertoire courant>
ATTENDRE <Clic souris bouton gauche>
<récupérer le nom du fichier cliqué dans NomFichierTexte>
<Ouvrir le fichier NomFichierTexte et l'afficher dans la fenêtre n°1>
................................
................................
CAS Inserer:
<inserer du texte à l'emplacement du curseur>
CAS Copier:
lt;Copier le texte sélectionné dans TexteSelectionné>
................................
................................
AUTRES CAS:
SORTIR «Commande inconnue» // Vers Fenêtre 1
FINCAS
FIN TANT QUE
FIN
FONCTION AFFICHER_DATE
var DateCourante en numerique
ENTRER DateCourante // DEPUIS l'horloge interne
SORTIR DateCourante // VERS Fenêtre 2
FIN FONCTION
Nous voyons ici que l'algorithme principal supporte l'éditeur de texte: après avoir
affiché les menus des applications «traitement de texte» et «horloge» dans les
fenêtres et installé le gestionnaire d'événement AfficherDate associé au
signal de survenue d'une seconde ronde, il entre dans une boucle de scrutation des commandes
sélectionnées par l'utilisateur de l'éditeur de texte.
Lorsque l'événement «seconde ronde» survient, quelle que soit l'instruction en
cours, le processeur se déroute vers la fonction AfficherDate: il va alors acquérir la date
courante et l'afficher dans la fenêtre n° 2, puis revenir exécuter l'algorithme principal
au point où il l'avait quitté.
Dans cet exemple, le traitement de l'affichage par un gestionnaire d'interruption s'impose car l'algorithme
principal comporte déjà une attente des commandes de traitement de texte, dont la survenue
dépend de l'utilisateur: plusieurs dizaines de secondes peuvent s'écouler entre deux commandes,
pendant lesquelles le flot de commandes serait bloqué sur cette attente. Il est donc impossible
d'utiliser une autre attente pour détecter le signal «seconde ronde».
L'utilisation d'un gestionnaire d'interruptions permet donc de garantir que l'affichage de l'heure se fera
toutes les secondes, quel que soit le comportement de l'utilisateur de l'éditeur de texte.
IV.2.ANNEXE II: LA NOTION D'OBJET:
IV.2.1.GENERALITES:
La notion d'objet dérive à la fois de la notion de procédure et de la notion de structure.
Elle résulte de la volonté de rassembler en une même entité les traitements et
les données sur lesquelles ces traitements travaillent, de façon à cacher à
l'utilisateur le détail de ces traitements (encapsulation);
Un objet est donc une structure de données qui contient à la fois des variables et des
procédures de traitement de ces variables.
IV.2.2.ATTRIBUTS ET METHODES:
L'exemple suivant représente un objet appelé DOCUMENT:
IV.2.2.1.LES ATTRIBUTS:
Nous voyons que l'objet DOCUMENT encapsule des données, que l'on appelle également
«ATTRIBUTS» de l'objet.
- Par défaut, un attribut est accessible pour toutes les procédures internes de l'objet
(c'est une donnée GLOBALE de l'objet) et non accessible de l'extérieur de l'objet.
- Ces attributs peuvent être rendues accessibles de l'extérieur de l'objet. On dit alors
qu'ils sont PUBLICS. Sinon, ils sont dits PRIVES.
L'accès à un attribut public depuis un algorithme externe à l'objet se fait de la
manière suivante:
<Nom d'objet>.<Nom d'attribut>
EXEMPLE: Accès à l'attribut Selection: DOCUMENT.Selection
REMARQUE:
Nous voyons que le mode d'accès à un attribut d'un objet est identique au mode
d'accès d'un élément d'une structure.
IV.2.2.2.LES METHODES:
Cet objet encapsule d'autre part un certain nombre de procédures. Ces procédures sont
appelées «METHODES». Les méthodes sous des procédures qui peuvent
être activées de l'extérieur de l'objet. Elles ont accès à tous les
attributs de cet objet.
On accède à une méthode depuis un algorithme externe à l'objet de la même
manière que pour un attribut:
<Nom d'objet>.<Nom de la méthode> ( <liste d'arguments> )
EXEMPLE: Accès à la méthode InsererTexte:
DOCUMENT.InsererTexte ( <Texte> )
IV.2.2.3.LA DEMARCHE D'ENCAPSULATION:
Revenons à l'exemple précédent. L'objet document renferme un attribut appelé
Texte, qui représente le texte d'un document. Il offre d'autre part au «monde
extérieur» un certain nombre de méthodes qui permettent de travailler sur ce document. On
peut ainsi:
- Afficher le texte
- Déplacer un curseur dans le texte
- Insérer du texte à l'emplacement du curseur
- Sélectionner une partie du texte
- Copier la sélection
- Couper la sélection
- Réafficher le texte
- etc...
L'objet se présente donc comme une interface permettant d'éditer un document. L'objet permet de
faire abstraction de la complexité des opérations listées ci-dessus pour ne s'occuper que
de leur résultat. Cette démarche par encapsulation représente une des
caractéristiques principales de la conception par objets.
IV.2.3.NOTIONS DE CLASSE D'OBJETS ET D'INSTANCIATION:
IV.2.3.1.DEFINITION:
Un deuxième aspect de la conception par objets est la notion de «CLASSE» d'objets. Nous
avons vu que la notion d'objet présente certaines similitudes avec la notion de structure. Il s'agit en
fait d'une structure particulière qui encapsule non seulement des données (les attributs), mais
aussi du code exécutable (les méthodes).
De ce fait, de la même façon qu'un TYPE STRUCTURE, une fois défini, peut être
utilisé comme modèle pour déclarer des structures de même type, un objet peut
être considéré comme un modèle, pouvant servir à déclarer d'autres
objets de même type.
VOCABULAIRE:
- Un objet ainsi utilisé comme modèle sera appelé CLASSE d'objets.
- L'action de déclarer un objet à partir d'une CLASSE se dit: «INSTANCIER»
cette classe (c'est à dire créer une instance, une copie de cette classe).
IV.2.3.2.DECLARATION D'UNE CLASSE:
La plupart des langages de programmation utilisent pour déclarer une classe un schéma
syntaxique proche de ce qui suit:
CLASSE <Nom de classe>
<Déclaration des attributs>
<Déclaration des méthodes>
FIN CLASSE
EXEMPLE:
CLASSE Document
// Déclaration des attributs:
var Texte en chaîne de caractères
var DateModification en numerique
// Déclaration des méthodes:
// - Méthode InsererTexte
PROCEDURE InsererTexte ( var Texte_a_Ajouter en chaîne de caractères )
....................................
....................................
....................................
FIN PROCEDURE
// - Méthode PositionnerCurseur
PROCEDURE positionnerCurseur ( var X en numerique, var Y en numerique )
....................................
....................................
....................................
FIN PROCEDURE
etc...
FIN CLASSE
IV.2.3.3.INSTANCIATION D'UNE CLASSE:
La plupart des langages de programmation utilisent pour déclarer une classe un
schéma syntaxique proche de ce qui suit:
OBJET <nom du nouvel objet> = NOUVEAU <nom de la classe d'objet>
EXEMPLE:
OBJET MonDocument = NOUVEAU Document // crée un objet «MonDocument»
sur le modèle de la classe Document.
REMARQUE:Dans la plupart des langages de programmation, l'opérateur
d'instanciation est représenté par le mot-clef «new»
IV.2.3.4.CONSTRUCTEURS ET DESTRUCTEURS:
Dans le cas d'un langage de programmation, l'opérateur new déclanche
l'exécution d'une méthode particulière de la classe appelée
CONSTRUCTEUR, et dont une caractéristique est d'avoir le même nom que la
classe. Cette méthode est ajoutée automatiquement à toute classe. Elle n'a
donc pas besoin d'être déclarée.
Cependant, dans le cas ou le constructeur n'est pas déclaré (constructeur
implicite), sa seule fonction est de réserver en mémoire un espace
équivalent à un objet de la classe et de définir un pointeur d'accès
à cet espace: cette fonction n'a évidemment aucune utilité en algorithmique.
En revanche, il est possible de déclarer un constructeur comme toute autre méthode,
ce qui permet d'y inclure des traitements d'initialisation de l'objet.
EXEMPLE: si l'on définit une classe Arbre comportant les attributs
TypeArbre et AgeArbre, il peut être intéressant de définir la méthode
constructeur de la manière suivante:
PROCEDURE Arbre ( Type en chaîne de caractères, Age en numérique )
TypeArbre ← Type
AgeArbre ← Age
FIN PROCEDURE
Ce constructeur permettra de créer des objets Arbre en initialisant leurs attributs:
MonArbre = NOUVEAU Arbre ( "platane", 10 ) crée un
platane de 10 ans. La notion de constructeur peut donc avoir son utilité en algorithmique
pour personnaliser les objets à la création.
En ce qui concerne les DESTRUCTEURS, ce sont des méthodes implicites qui sont
appelés lorsqu'on détruit un objet (Opérande DELETE), ce qui entraîne la
désallocation de ses ressources (en particulier, sa zone mémoire est
libérée). Les destructeurs n'ont pas d'utilité en algorithmique.
IV.2.3.5.ACCÈS À UN ATTRIBUT OU À UNE MÉTHODE:
L'accès à un attribut ou à une méthode suit en général la même
syntaxe que l'accès à un membre d'une structure:
- MonDocument.DateModification // Donne accès à l'attribut DateModification de l'objet
MonDocument.
MonDocument.AjouterTxt (...) // Permet d'activer la méthode AjouterTxt de l'objet
MonDocument.
ATTENTION:
on voit ici qu'on accède à l'objet MonDocument et non à la classe DOCUMENT: en effet,
comme dans le cas d'une structure, seul un OBJET a une existance réelle. Une CLASSE n'est qu'un type
d'objet, un modèle abstrait: il est impossible de charger une donnée dans un attribut ou
d'appeler une méthode d'une classe avant que cette classe ait été instanciée
par la déclaration d'un objet de cette classe.
IV.2.4.NOTION D'HERITAGE:
IV.2.4.1.DEFINITION:
Le mécanisme de l'HERITAGE permet de construire une classe à partir d'une ou de plusieurs autres
classes. Lors d'un héritage, la classe héritière hérite des attributs et
méthodes de la classe «donatrice» (ou des classes donatrices). Lorsqu'une classe
hérite d'une seule classe, l'héritage est dit «simple», sinon il est dit
«multiple».
Les langages informatiques emploient souvent les termes de «classe DERIVEE» et
«classe DE BASE» pour désigner respctivement une classe
«héritière» et une classe «donatrice». Par la suite, nous utiliserons
ces termes.
IV.2.4.2.DECLARATION D'UNE CLASSE DERIVEE:
- Lors de la déclaration d'une classe par le mécanisme de dérivation, il est
possible de doter cette nouvelle classe (outre les attributs et les méthodes
héritées de ses classes de base) de nouveaux attributs ou de nouvelles méthodes.
- Il est également possible de remplacer les méthodes héritées par des
méthodes de même nom, mais dont l'algorithmique interne ou les arguments d'appel sont
différents. Ce mécanisme est appelé «surcharge» de méthode.
La dérivation permet donc un enrichissement ou une spécialisation de la ou des
classes de base.
REMARQUE: Dans la plupart des langages objets, lorsqu'une classe dérivée ne
déclare pas explicitement de constructeur, son constructeur implicite fait appel aux constructeurs
des classes de base. C'est ce comportement que nous supposerons ici.
IV.2.4.3.SYNTAXE DE DECLARATION D'UNE CLASSE DERIVEE:
Nous proposons la syntaxe suivante (tirée du langage C++):
CLASSE <Nom classe dérivée>
: <Nom classe de base 1>,...
,<Nom classe de base n>
<déclaration des attributs spécifiques de la classe dérivée>
<déclaration des méthodes spécifiques ou surcharges des méthodes
héritées>
FIN CLASSE
IV.2.4.4.EXEMPLE DE DERIVATION DE CLASSES:
Supposons que, comme dans le premier exemple, nous voulions concevoir une classe permettant d'éditer
un texte et supposons que nous disposions déjà de deux classes. La classe Afficheur et la classe
SaisieTexte, dont voici les déclarations:
CLASSE Afficheur
var Texte en chaîne de caractères // attribut Texte
Procedure AfficherTexte ()
SORTIR Texte
FinProcedure
FIN CLASSE
CLASSE SaisieTextevar Texte en chaîne de caractères
Procedure InsérerTexte ( var NouveauTexte en chaîne de caracteres )
Texte ← NouveauTexte
FinProcedure
Procedure EffacerTexte ()
Texte ← <Chaîne vide>
FinProcedure
FIN CLASSE
Une classe qui hériterait de ces deux classes serait capable de saisir un texte et de l'afficher, ce
qui constitue une partie du comportement d'un éditeur. Créons une classe dérivée
de ces deux classes (nous l'appellerons «EditeurSimple»):
CLASSE EditeurSimple: Afficheur, SaisieTexte
var DateModification en numerique
Procedure InsérerTexte ( var NouveauTexte en chaîne de caracteres )
Texte ← NouveauTexte
DateModification ← < Date courante >
FinProcedure
FIN CLASSE
Cette nouvelle classe héritera des attributs et méthodes des deux classes de base. D'autre part,
elle possède un nouvel attribut (DateModification) et la méthode InsererTexte est
surchargée. En effet, son algorithme interne a été modifié pour intégrer la
sauvegarde de la date courante dans l'attribut DateModification lors de l'insertion d'un texte.
La nouvelle classe possèdera donc les attributs Texte et dateModification et les méthodes
AfficherTexte, InsererTexte et EffacerTexte. D'autre part, la méthode InsererTexte a été
surchargée.
Par instanciation de EditeurSimple (OBJET MonEditeurSimple = NOUVEAU EditeurSimple), nous aurons accès
uniquement aux méthodes:
- MonEditeurSimple.InsererTexte ();
- MonEditeurSimple.AfficherTexte();
- MonEditeurSimple.EffacerTexte();
Pour créer un éditeur complet, il va falloir rajouter un certain nombre de comportements
(sélectionner, copier, coller) et des attributs permettant de repérer et modifier la position
du curseur et de sélectionner une partie du texte. On obtiendra une nouvelle classe EditeurComplet en
effectuant:
- Une dérivation de la classe EditeurSimple
- L'ajout des attributs Selection, X_PositionCurseur et Y_PositionCurseur
- L'ajout des méthodes PositionnerCurseur, SelectionnerTexte, CopierSelection, CouperSelection,
CollerSelection
- Une nouvelle surcharge de la méthode InsererTexte pour permettre d'insérer une
chaîne de caractères à un endroit donné du texte.
La déclaration de EditeurComplet sera semblable à ce qui suit:
CLASSE EditeurComplet: EditeurSimple
// Attributs ajoutés:
// -------------------------
var Selection en chaîne de caractères
var X_PositionCurseur en numerique
var Y_PositionCurseur en numerique
// Procedures surchargées
// -------------------------
Procedure InsérerTexte ( var NouveauTexte en chaîne de caracteres )
var Rang en numerique
<calcul du rang du caractère pointé par le curseur dans la chaine texte>
Texte (Rang) ← NouveauTexte
DateModification ← < Date courante >
FinProcedure
// Procedures ajouté
// --------------------
Procedure PositionnerCurseur ()
...........................
FinProcedure
Procedure SélectionnerTexte ()
...........................
FinProcedure
Procedure CopierSelection
...........................
FinProcedure
Procedure CouperSelection ( .....)
...........................
FinProcedure
Procedure CollerSelection ( .....)
...........................
FinProcedure
Procedure AfficherTexte ( .....)
...........................
FinProcedure
FIN CLASSE
IV.2.5.CONCLUSION SUR LA CONCEPTION PAR OBJETS:
Nous n'avons abordé ici que les notions de base de la conception et de la programmation par objets.
Nous avons essayé de présenter les mécanismes d'une façon la plus
indépendante possible des langages de programmation existants, de façon à nous concentrer
sur leur logique propre. Cependant, dans le cadre de l'algorithmique, il est impossible d'aborder certains de
leurs aspects, car ils sont liés à leur implémentation sur les systèmes
informatiques.
Le fait de prendre en compte les mécanismes du monde «objets» en algorithmique a
l'avantage de permettre l'utilisation de cette discipline dès la phase de conception
détaillée d'une démarche objets.
D'autre part, le mécanisme de l'héritage permet de constituer des arborescences de classes
dérivées les unes des autres. Associé au mécanisme d'instanciation des classes, il
autorise un très haut niveau de réutilisation des codes qui permet de rationaliser et minimiser
l'effort de production. Cet aspect peut être utilisé en algorithmique.
IV.3.ANNEXE III: LES TYPES DE DONNEES EN PROGRAMMATION:
En algorithmique, aucune contrainte de taille mémoire ne pèse sur le développeur.
Celui-ci peut donc négliger cet aspect lorsqu'il déclare des données.
Dans un programme informatique, en revanche, la taille des données déclarées peut
revètir une grande importance: lorsque l'on déclare un tableau de 1000000 de nombres, le fait
que chaque nombre occupe 2 ou 8 octets n'est évidemment pas sans conséquence.
Il est donc nécessaire de disposer de beaucoup plus de types numériques prédéfinis.
Pour cela, on distinguera deux types principaux:
- Les nombres ENTIERS (INTEGER en anglais)
- Les nombres dits "FLOTTANTS" (FLOAT en anglais), qui correspondent aux nombres non entiers, c'est à
dire comportant une partie décimale.
REMARQUE:
l'appellation FLOTTANT (ou FLOAT) fait référence au procédé de codage
binaire utilisé pour ces nombres: la position de la virgule (appeléée "caractéristique") y est
codée dans un champ binaire distinct de celui des bits "significatifs" (appelé "mantisse").
Puis, on subdivisera ces types en fonction de la capacité de la donnée (valeur maximale
codable) et de la prise en compte ou non des valeurs négatives. Le tableau suivant résume cette
démarche:
TYPE PREDEFINI |
LONGUEUR EN OCTETS |
CAPACITE MAXIMALE |
UNSIGNED BYTE (octet non signé) |
1 (soit 8 bits) |
De 0 à 255 |
BYTE (octet signé) |
1 (soit 8 bits) |
De -128 à +127 |
UNSIGNED INT («integer» ou entier simple non signé) |
2 (Soit 16 bits) |
De 0 à 65535 |
INT ( «integer» ou entier simple signé) |
2 (Soit 16 bits) |
De -32768 à +32767 |
UNSIGNED LONG INT (entier long non signé) |
4 (Soit 32 bits) |
De 0 à 4294966295 |
LONG INT (entier long signé) |
4 (Soit 32 bits) |
De -2147483648 à +2147483647 |
FLOAT (Flottant court) |
4 (Soit 32 bits), 3 octets pour la valeur et un pour la position de la virgule) |
Infinie... |
DOUBLE FLOAT (Flottant double) |
8 (Soit 64 bits), 7 octets pour la valeur et un pour la position de la virgule) |
Infinie... |