POO NotesCours
POO NotesCours
Programmation Avancée
(AV&SD)
&
Étude de
la Programmation en
Langage C/C++
Notes de
Cours en
Informatique :
Révision du cours
(SD & AV & POO)
Programmation Avancée
&
Programmation
Orientée Objet
&
LP C/C++
(Selon le cours du Prof. Dr. A. BENHSAIN)
Nota Bene :
- Les abréviations écrites dans ce Fiche de Notes de Cours sont des Acronymes ou des notations
abrégés :
- RQ : Remarque ;
- P.S : post-scriptum, qui signifie « écrit après » ou « annexe » ;
- N.B : Nota Bene, qui signifie on noter bien que ..., ou à noter que … ;
- LP : Langage de Programmation
- LP C : Langage de Programmation C
- LP C++ : Langage de Programmation C++
- LP C/C++ : Langage de Programmation C & C++
- FCT : fonction ;
- PRG : Programme (Informatique) ;
- Lvalue : référence de la variable (nom, étiquette ...) ; // Exp : int a ; → a est une lvalue !!
- Rvalue : Expression calculable ou une valeur affectable à une Lvalue ;
- LIFO : Last In, First Out
- FIFO : First In, First Out
- ISO: International Organization for Standardization
- ASCII : American Standard Code for Information Interchange
(Code américain normalisé pour l'échange d'information) ;
- Le LP C ne connais que la transmission par valeur, et quand un paramètre est transmis par valeur
c'est une nouvelle copie (une autre variable de même valeur) se crée dans la fonction et si on
modifie cette copie alors la variable originale ne subira aucun changement, et dans ce cas la si on
veut modifier la variable transmit donc il faut passer l'adresse comme valeur et grâce au
formalisme de pointeur que supporte le LP C la variable sera modifier dans la fonction :
type fonction(type1 var1 , type2 var2) ; // passage par valeur des paramètres
type fonction(type1 * var1 , type2 * var2) ; // Passage des adresses des paramètres par valeur
• Exemple :
→ Exemple :
Soit à réaliser la fct polymorphe inc() , qui incrémente un objet selon sa nature :
// surcharges integer :
// surcharges char :
// surcharge string :
- Le type string, à l'instar du type du même nom des autres langages de programmation
fournit une meilleure gestion des chaînes de caractères. Pour utiliser ce type, il faut
mettre au début du PRG :
#include <string>
using namespace std;
- Nous pouvons utiliser ce type à la place de char* pour mieux gérer les strings.
➢ RmQ :
Ces 2 surcharges ont presque une signature similaire, la différence entre les 2
prototypes est dans le type de passage du 1er paramètre à la fct. Or les IDEs
(MS VisualStudio, …) acceptent les 2 surcharges en même temps. Dans le cas où
on appelle la fct inc() avec des constantes alors le compilateur ne connaît pas
d’ambiguïté car il sait qu’il doit appeler la 2 surcharge , mais si on appelle la fct
ème
inc() avec au 1 paramètre un lvalue (Left Value), alors là, le compilateur va sortir
er
une ERREUR car il est dans l’ambigüité du choix entre les 2 surcharges .
Alors IL FAUT EVITER D’UTLISER COMME CES 2 SURCHARGES DANS
UN MEME PROJET !!!!!!!
** → Paramètres par Défaut :
// Exemple de prototype :
int inc(int&, int = 1);
// Exemple de définition
int inc(int &x, int pas)
{
return x += pas;
* Une fct peut recevoir plusieurs paramètres par défaut, qui doivent
nécessairement être les derniers de la liste de paramètres. Un paramètre par
défaut ne peut pas être suivis par un paramètre obligatoire.
- exemple de prototype :
int f(int &, int, int = 2, int = 0, int = 0);
réel.
ATTENTION :
La valeur par défaut ne peut être fournie qu’une seule fois, soit
dans le Prototype, soit dans la définition.
** → Les Fonctions Références :
o Exemple :
Définissons la fct mini() qui retourne la variable la plus petite parmi les 2
variables paramètres qu'elle reçoit , et qui permettrait par exemple
mini(a, b) += 30;
Le modificateur const placer devant la déclaration d'un paramètre formel (const int
a) interdit la modification, dans la fct de la valeur du paramètre.
• Exemple :
Nota Bene :
- type* const pointeur1 interdit la modification de la valeur du pointeur
pointeur1 , const type* pointeur2 interdit la modification de la valeur de
la variable sur laquelle pointe pointeur2 ;
- La valeur retourner par une fct peut aussi être déclarer " const ", pour empêcher
sa modification. C’est un modificateur utile lorsqu’une fct retourne un pointeur ou
un résultat par référence.
// Exemple de déclarations :
// Exemple d'invocation :
l'exécutable.
implicitement .
** → Variables et Fonctions static :
Une variable déclarée static dans une fct est créée en un seul exemplaire
partagé par toutes les invocations de la fct.
Chaque invocation de la fct trouve dans la variable la valeur qui y a
été laissée par l’invocation précédente.
La variable static est créée et initialisée au début du PRG avec
les variables globales (segment DS).
Une variable locale normale est créée et initialisée chaque fois que la fct
est activée puis détruite à la fin de l’activation. Elle est enregistrée dans la
PILE (segment SS).
Une variable locale static est une variable locale du point de vue de la
visibilité (la portée). Elle est une variable globale du point de vue de sa
durée de vie et de son emplacement dans la MC et de son initialisation.
Une fct ou une variable globale déclarée static dans un fichier n'est visible
o Exemple :
▪
Soient les 3 fichier-PRG [Link], [Link] et [Link], les fichiers d’un même projet C/C++ :
. int f()
. { int main()
//.... {
static int f() } f(); f(); f();
{ f(); return 0;
. //… }
.
. /* /*
Le vecteur K[] utilisée Le vecteur K[] ici
dans ce fichier sera sera celui défini et
} celui défini et crée créé par [Link] et f()
dans [Link] ici est celle définie
*/ dans [Link]
*/
CHAPITRE 2 :
Nous parlons souvent d’un ADT (Abstract Data Type) ou TDA (Type de
Données Abstrait), ce qui consiste en une extension aux types de données
disponibles dans le langage de programmation. Un type de données consiste en un
ensemble de valeurs et un ensemble d’opérations qui peuvent être appliquées à ces
valeurs.
Plusieurs LPs connaissent le type de données nombre réel "double" : nous
pouvons dé finir des variables (de ce type) et utiliser des constantes (de ce type).
Nous pouvons aussi manipuler ses valeurs par un ensembles de fcts et d’opérations
( + , * , / , (int) , pow(double, int) , sqrt() ). Et pratiquement
tous les langages de programmations connaissent le type de nombre "int" : nous
pouvons définir et utiliser des constantes de ce type. Nous pouvons aussi
manipuler ces valeurs par un ensemble de fonctions et d’opérateurs (+, *, / , %
, (double), (char),pow(), sqrt(),floor(),ceil(),fabs()).
L’ADT : La définition d’un ADT consistera ainsi à définir ses valeurs et les
opérations que ces valeurs (du ADT) peuvent subir. La manière la plus élégante
pour définir un ADT consiste à le définir sous la forme d’une classe (class).
Par Exemple, le type des nombres complexes n’existe pas en LP C/C++, mais
C/C++ nous permet de définir ce type sous la forme d’une classe, avec ses
valeurs possibles et un ensemble d’opérations correspondantes, se sera un ADT
complex, qui résumera (abstract) le type mathématique des nombres complexes.
class complex
{
public: // Explicite en C/C++ pour les classes (class) , implicite en C/ C++ pour Struct
double Module()
{
return sqrt(pow(a, 2)+ pow(b, 2));
}
complex operator+(complex rhs)
{
return complex(a + rhs.a, b + rhs.b);
}
return *this;
}
complex operator*(complex);
private: // Implicite en C/C++ pour les classes (class) , Explicite en C/ C++ pour
Struct double a, b;
};
// Exemple d'invocation :
Z += W; // équivalente à : [Link]+=(W);
(Y += W) = Z; // Comme avec les type standard
Y*W ; // équivalente à : [Link]*(W);
→ RmQ - ‘ sur les classes (class), avec l’exemple de class complex ’ :
- La phrase class permet de créer la classe complex. Cette class ce compose d'un ensemble de champs (a et b), et un
ensemble de méthode (fonctions). Nous disons que ces champs et ces méthodes constitues les membres ou attributs de
la class. Nous disons qu'ils sont encapsulés pour constituer une class. c'est le phénomène de l’encapsulation.
- La description (déclaration) de la class est similaire à un manuel d'utilisation des objets qui appartiennent à la class cette
description est appliqué à chaque objet qui appartient à la class, ou instance de la class . La class elle-même n'existera
que par ces objets qui auront chacun sa propre copie a et b, et se partageront la même copie de méthodes.
- Les champs dans cet exemple sont déclarés dans une section de visibilité private: ils ne sont accessibles (visibles) que
par les méthodes de la class. Cela pour les protéger des mauvaises manipulations et pour faciliter les modifications
de la structure interne de la class. Ces membres privés de la class restent accessibles via les méthodes publiques de
la class (exemple : le constructeur() et Module() ) .
- Les méthodes sont ici déclarées dans une section public : elles sont visibles aussi de l'extérieur des méthodes de la
class. Elles constituent l'interface de la classe, c.à.d. la partie mise à disposition de l'utilisateur de la classe pour
manipuler ses objets.
- La méthode complex() porte le nom de sa class. Elle est alors un constructeur de la class.. Elle construit les
instances de la class et ne retourne aucune valeur. Un constructeur sera invoqué chaque fois qu'une instance
de class est créée pour la construire.
- Les méthodes Module(), operator+=() et le constructeur sont définis à l'intérieur de la déclaration de la class . Ce sont
alors implicitement des fonctions inline.
- La méthode operator*() est définie à l'extérieur de la classe, c'est une méthode à appel classique (non inline). Pour
indiquer son appartenance à la class complex, au moment de sa définition, nous utilisons l'opérateur de résolution
de portée ‘ :: ’ .
- Dans la programmation classique la fonction Module() serait invoqué pa la syntaxe Module(X) , où X est un
paramètre qui subit la fct. Cette syntaxe accorde le rôle le plus important à la fonction.
- L'invocation dans la POO : [Link](), donne à l'objet X l'importance qu’il mérite. C'est X qui exécute Module(). X est
"responsable" de l'exécution de la méthode.
- Lorsque l'appel est traduit dans le langage machine, X redevient un paramètre, dans le sens classique du terme.
- Dans l'appel [Link](), nous disons que C1 est le paramètre implicite de la méthode Module(), de C1+= C2 , et de
toutes les méthodes de la class invoquée à partir de C1. Tous les champs de la class manipulés par les méthodes
de la class, sont implicitement ceux du paramètre implicite, sauf si le propriétaire du champ est explicitement fourni
(Exemple : a += rhs.a) .
- Le compilateur permet l'accès au paramètre implicite, soit automatiquement, soit via le pointeur this fourni par le
compilateur, qui POINTE vers le paramètre implicite. C’est comme si la méthode operator+=() était définie par :
complex operator+=(complex *this, complex rhs){this->a += rhs.s ;... return *this;}, et
invoquée par Module(&C1,C2);
Le pointeur this est utilisé lorsque nous sommes obligés de l’utilisés, et quelques fois pour rendre le code plus
clair. Exemple :
La différence entre les codes :
if (X.a < a + Y.a) et if(X.a < this->a + Y.a)
- Une méthode de la class ne peut être utilisé que par l'objet de la class. Alors les champs de la class manipulés
par une méthode sont ceux de l'instance qui appelle la méthode ( [Link]() retournerait X.a et
[Link]() retournerait Y.b ).
- Un attribut (champ ou membre) est déclaré static dans une class est créée en un seul exemplaire partagé par
toutes les instanciations des objets de la class, cet attribut static est le même (aura la même valeur) pour tous
les objets de cette class.
> Exercices du Chapitre 2 (Classes & Objets) :
Exercice 1 :
Définir la class complex, le types mathématiques des nombres complexes, ainsi
que ses opérations .
Exercice 2 :
Définir la class fraction, qui permet de manipuler les nombres fractionnels
représenté par un numérateur et un dénominateur, il faut définir le constructeur et
ses opérations.
CHAPITRE 3 :
** → Les Constructeurs :
Exemple :
DéfinissonsString qui fournira l'ADT chaîne de caractères mieux géré
que le type char*.
Résolution :
class String
{
public:
String(char* ival = "")
{
val = new char[strlen(ival) +
1]; strcpy(val, ival);
}
private: char*
val;
};
RmQ : Pour cette class String nous sommes obligés de définir le vecteur dynamique pour
Quand on ne définit aucun constructeur pour une class, le compilateur fournit son constructeur, qui ne reçoit
aucun paramètre. C'est donc un constructeur par défaut (parce qu’il reçoit 0 paramètres). Lorsque nous
définissons au moins un constructeur pour une class, le compilateur ne fournis pas son constructeur.
Si nous défissions au moins un constructeur pour une class, et si aucun de ces constructeurs n'est
** → Listes d'initialisation :
Une Liste d’initialisation, dans un constructeur, permet d'initialiser les valeurs des membres de la class.
Par Exemple :
Si Par exemple nous associons à chaque objet String une constante MAXLEN qui
indiquera la taille maximale permise à la chaine valeur de l'objet, dans ce cas les
champs de la class devient :
private:
const int MAXLEN;
char* val;
Et le constructeur devient :
String(int iMAXLEN = 100, char* ival = "") : MAXLEN(iMAXLEN) , val(new char[MAXLEN + 1])
{
strcpy(val, ival);
}
ATTENTION :
L'ordre dans lequel les champs membre de la class sont initialisées par la liste d'initialisation est l'ordre dans
lequel ils sont déclarés, l'ordre de la liste d'initialisation n'est pas pris en compte. Dans notre exemple MAXLEN
doit être déclaré avant val.
La liste d'initialisation est ainsi le seul endroit où on peut initialiser la constante est d'invoqué le constructeur de
la class mère (*important). (class mère ???)
Exemple :
Surchargeons l'opérateur de l'affectation pour S1 = "Samira Said"
→ Résolution :
String operator=(const char* ival)
{
delete[] val;
val = new char[strlen(ival) +
1]; strcpy(val, ival) ;
return *this;
}
** → Le Destructeurs :
Le destructeur est une méthode qui porte le nom de la class précédé par ~ et ne reçoit aucun
paramètre et ne retourne aucune valeur. Il et invoqué implicitement chaque fois qu'un objet doit
être détruit. Il est fourni par le système quand non défini par le programmeur. On le défini
explicitement normalement pour récupérer la valeur d'un objet avant sa destruction et pour libérer
l'espace dynamique, exemple :
~String()
{
delete[] val;
}
** → Le Constructeur de Copie :
Le constructeur de copie est une méthode fournie par le compilateur lorsqu'elle n'est pas définis par le
programmeur. Elle construit un nouvel objet comme copie d'un objet qui existe déjà. Elle est invoquée
dans les 3 cas suivant :
• La construction de la valeur retournée par une fct, par valeur, par exemple l'operator=() ci-dessus retournera
par valeur une copie de *this .
Le constructeur de copie fourni par le compilateur ne connait de l'objet que les champs statiques. Il
construit des copies des champs statiques mais pas des champs dynamiques (une copie de val mais
pas du vecteur pointé par val). Alors val et sa copie pointeront vers le même vecteur.
Le constructeur de copie de la class CL à normalement le prototype :
CL(const CL&);
(Avec & est obligatoire ,const est recommandée)
**→ Exemple :
int strlen(String S)
{
return strlen([Link]);
}
Cette fct est définit au niveau global elle n'a pas le droit d'accéder à val, de visibilité private.
Pour résoudre ce problème nous pouvons déclarer cette fct amie (friend) de la
: c
l
a
s
class String
{
s
S
... t
... r
i
friend nint strlen(String);
... g
...
};
Une fct amie d'une class a tous les privilèges des méthodes membre de la class qui
consiste à accéder au champs private et protected de la class.
> Exercices du Chapitre 3,4 (Classes&Objets, Constructeurs, Destructeurs, Opérateurs et FCTs Amies) :
Enoncé de l’exercice :
• Soit à réaliser un ADT String qui définit le type de données chaîne
de caractères, et qui saura mieux gérer les chaînes de caractères.
(L’ADT String n’est pas la class string prédéfinit dans la bibliothèque <string>)
o Exemple :
Soit :
int a = 20;
Et soit :
(cout << a) retourne par référence cout (l’objet du flux de sortie) décalé
à gauche par la valeur de a (pour qu’il soit pris en compte par le flux de sortie) ,
qui sera elle-même décalé à gauche par endl (retour chariot), pour enfin afficher
le tous dans la console.
/!\ ATTENTION :
"l’operator <<" ou Décalage à gauche ou "Shift Left" dans ce cas est une
surcharge de << , et qui opère sur la class ostream et qui insert la valeur de la
variable placer à droite dans l’output pour qu’elle soit affichée ;
***→ Surcharge de l'opérateur << : (Source : MSDN C/C++ - << pour OSTREAM)
Les flux de sortie utilisent l'opérateur insert (<<) pour les types standard. Vous
pouvez également de surcharger l'opérateur d'<< pour vos propres classes.
Exemple :
L'exemple de fonction d'write indiquée l'utilisation d'une structure d'Date. Une date est un candidat
idéal pour la classe actuelle C++ dans laquelle les membres de données (mois, jour, et année) sont
masqués de la vue. Un flux de sortie est la destination logique pour afficher une telle structure. Ce
code affiche une date à l'objet d'cout :
Date dt( 1, 2, 92
); cout << dt;
Pour obtenir cout de recevoir un objet d'Date après l'opérateur insert, surchargez l'opérateur d'insertion
pour identifier un objet d'ostream à gauche et un Date à droite. La fonction surchargée d'opérateur <<
doit être déclarée comme une fonction friend de la classe Date ce qui peut accéder à des données
privées dans un objet d'Date.
// overload_date.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Date
{
private:
int mo, da,
yr; public:
Date(int m, int d, int y)
{
mo = m; da = d; yr = y;
}
friend ostream& operator<<(ostream& os, const Date&
dt); };
int main()
{
Date dt(5, 6,
92); cout << dt;
L'opérateur surchargé retourne une référence à l'objet d'origine des ostream, ce qui signifie que vous
pouvez combiner des insertions :
Soit :
int a , b;
Et soit :
(cin >> a) retourne par référence cin (l’objet du flux d’entrée) décalé à droite par la valeur de a (pour qu’il soit
pris en compte par le flux d’entrée ,c’est-à-dire que ce qui sera tapé dans le clavier sera affecté à a ) , qui sera elle-même
décalé à droite par b, pour enfin lire deux valeurs du clavier et les affecter successivement à a puis b .
/!\ ATTENTION :
"l’operator >>" ou Décalage à droite ou "Shift Right" dans ce cas est une surcharge de << , et qui opère
sur la class istream et qui insert la valeur lue du clavier à la variable placer à droite ;
***→ Surcharge de l'opérateur >> : (Source : MSDN C/C++ - >> pour ISTREAM)
Surchargeons l’opérateur >> (operator>>()) pour la class istream afin qu’on puisse lire du clavier un objet
de la class String :
Les flux d'entrée utilisent l'opérateur d'extraction (>>) pour les types standard. Vous pouvez écrire des opérateurs
d'extraction similaires pour vos propres types ; votre succès dépend de l'utilisation de l'espace blanc avec précision.
Voici un exemple d'un opérateur d'extraction pour la classe Date présentée précédemment :
Même si une fct que nous définissons au niveau global n'a pas besoin d'accéder
aux membres privés d'une class, il est recommandé de la déclarer amie de la
class, si elle "travail" pour la class. Cela pour montrer sa relation étroite avec la
class et pour qu'elle soit visible dans la déclaration (manuel) de
la class.
CHAPITRE 6 :
- Nous pouvons surcharger un opérateur déjà utilisé pour les types primitifs, mais nous ne pouvons pas
créer de nouveaux opérateurs (par exemple <>).
- Nous ne pouvons modifier ni la priorité d'un opérateur, ni son arité (le nombre de paramètre qu'il
reçoit), ni son associativité.
- On ne peut surcharger un opérateur que si au moins l'un de ses opérandes est membre d'une classe
ADT (on ne peut pas définir par exemple : int operator/(int, int);).
- Plusieurs Opérateur sont commutatifs pour les types primitifs (+,*) , mais ils ne sont pas
automatiquement sur les ADT. Si nous avons besoin de la commutativité nous devons la déclarer,
exemple :
String operator*(String S, unsigned n)
{
String Res = "";
while (n--)
Res = Res + S;
return Res;
}
Exemple d’invocation :
- De façon similaire au cas de la commutativité, la majorité des opérateurs binaire (+,-,/,* , ...) peuvent
être fusionner à l'affectation (+=,/=,...) , et ainsi A = A + B <=> A += B .
Cela n'est pas automatique pour les ADT. Par exemple, nous ne pouvions pas écrire dans le dernier
exemple Res += S. pour pouvoir le faire il faut définir String operator+=(String rhs);
- Les opérateurs surcharger ne peuvent pas avoir un paramètre par défaut.
- La surcharge d'un opérateur peut lui donner un sens qui n'a rien à voir avec l'interprétation qui lui
est communément associé lorsqu’il est appliqué aux types primitifs. Mais, par déontologie, il est
fortement recommandé de respecter l'interprétation reconnue de l'opérateur.
CHAPITRE 7 :
Normalement cet opérateur est surchargé sur les classes desquelles chaque membre se compose
d'un ensemble de valeurs plus simples d'un type T ;
Le prototype sera normalement : T &
operator[](
type
énuméré);
Note & Remarque sur les types énumérés :
(article MSDN VisualC++ sur "enum")
Une énumération est un type défini par l'utilisateur (programmeur) qui se
compose d'un jeu de constantes intégrales nommées, appelées énumérateurs.
Syntaxe :
enum NomEnum{enum-list};
Exemple1 :
enum Jour { lundi, mardi, mercredi, jeudi, vendredi,
samedi, dimanche };
// dans ce cas : lundi représente 0 , ... , dimanche représente 6
Exemple2 :
enum ExempleEnum { enum1 = val1, enum2 = val2, … };
char &operator[](int i)
{
return val[i];
}
Exercice (Application) : définir une meilleure version de cette méthode (operator[]()) ;
Résolution :
RmQ : Les opérateurs [] et () ne peuvent être surchargés que comme des méthodes membre de la class et
non pas comme des fonctions friend, et cela car ces deux opérateurs sont très proches de la class où ils sont
surchargés ;
**→ Les Opérateur de Conversion en LP C/C++ :
Tout constructeur d’une class CL qui reçoit un paramètre unique de type T, est
aussi un opérateur de conversion du type T vers la class CL : il peut convertir une
valeur de type T en un objet de la class CL. Il peut être invoqué explicitement ou
implicitement par le Compilateur.
• Exemple :
String S1 = "Ali", S2 ;
operator char*()
{
return val;
}
Lorsque les objets d'une class sont volumineux (occupent beaucoup d'espace), nous préférons
recevoir l'objet original comme paramètre par référence (pour économiser l'espace nécessaire à
la copie du paramètre par valeur et les temps de la création de la copie et destruction). Alors
nous protégeons ce paramètre par const.
Nous avons alors un problème si nous avons une opération du type : *p = *q et p et q point vers
le même objet (càd S=S). Le test if(&rhs != this)évite la suppression de l'objet par
delete[] val.
String String::operator++(int)
{
String result = *this;
++(*this);
return result;
}
CHAPITRE 8 :
HERITAGE
(en LP C/C++)
→ Notes et Révisions du Cours sur « l’Héritage » :
A partir d'une class M appelée class Mère, nous pouvons définir (dériver)
une nouvelle class F appelée Fille, par la syntaxe suivante :
class f :public M
{
...
};
Alors, tous ce qui a dit pour la class M (toute la description) reste valable pour la
class F, sauf, éventuellement la visibilité de certains membre (champs ou fcts).
Nous disonsque la class F hérite de la class M. Nous pouvons ensuite ajouter
à (enrichir) la class fille de nouveaux attributs. Nous pouvons aussi modifier des méthodes
héritées.
Exemple, définissions la class IntFract qui représente les nombres sous la forme
d’un nombre entier associé à une fraction (exp 153 2/3).
Exemple :
IntFract K(28, 10), L(33, 6, 8);
L += K;
Ou la définition :
IntFract &operator+=(IntFract rhs)
{
Fraction X(
Fraction(PInt * den + num, den) += Fraction([Link] * [Link] + [Link], [Link])
);
return *this = IntFract([Link],[Link]);
}
**→ Méthodes Virtuelles et Polymorphisme :
Exemple :
const double PI = 3.14;
enum Color { blanc, jaune, bleu, vert, noir, rouge };
class FigureGeo
{
public:
FigureGeo(Color icoul = blanc) : coul(icoul) {}
protected:
Color coul;
};
public:
rectangle(double ilong, double ilarg, Color icoul = blanc)
: FigureGeo(icoul), longueur(ilong), largeur(ilarg)
{
if (longueur > largeur)
{
double sauv = longueur;
longueur = largeur;
largeur = sauv;
}
}
double surface()
{
return longueur*largeur;
}
protected:
double longueur, largeur;
};
public:
carre(double cote, Color icoul = blanc) :
rectangle(cote, cote, icoul)
{ }
private:
};
double surface()
{
return (rayon*rayon)*PI;
}
protected: double
rayon;
};
Exemples d’invocations :
int main()
{
FigureGeo FG;
rectangle Rec(28, 120,
noir); cercle C(85);
double SF = [Link]();
double SC = [Link]();
double SR = [Link]();
FigureGeo* pF[5];
int a;
for (int i = 0; i < 5; i++)
{
cin >> a;
if (a < 10)
pF[i] = new
FigureGeo(bleu); else if (a < 20)
pF[i] = new rectangle(25,10,blanc);
else
pF[i] = new cercle(25, blanc);
}
return 0;
}
***→ Important :
Toutes les substitutions d'une méthode virtuelle doivent avoir exactement le même
prototype ;
***→ Appel compilé et appel calculé :
LP C/C++, est l’un des rares langages POO qui supporte l’héritage multiple.
Exemple :
Nous voulons définir les classes : cylindre, parallélépipède, combiné. Pour cela,
nous allons définir la classe figureAVolume :
Annexe 1 :
1. Les opérateurs sont répertoriés par ordre de priorité descendant. Si plusieurs opérateurs apparaissent sur la même
ligne ou dans un groupe, ils ont la même priorité.
2. Tous les opérateurs d'assignation simple et composée ont une même priorité.
Une expression peut contenir plusieurs opérateurs avec une même priorité. Lorsque plusieurs
opérateurs de ce type apparaissent au même niveau dans une expression, l'évaluation se poursuit selon
l'associativité de l'opérateur, de droite à gauche ou de gauche à droite. Le sens de l'évaluation
n'affecte pas les résultats des expressions comprenant plus qu'un seul opérateur de multiplication (*),
d'addition (+) ou binaire au niveau du bit (& | ^), au même niveau. L'ordre des opérations n'est pas
défini par le langage. Le compilateur est libre d'évaluer de telles expressions dans n'importe quel
ordre, s'il peut garantir un résultat cohérent.
Seuls les opérateurs d'évaluation-séquentielle (,), AND logique (&&), OR logique (||), d'expression-
conditionnelle (? :) et d'appel de fonction constituent des points de séquence et garantissent par
conséquent un ordre particulier d'évaluation pour leurs opérandes. L'opérateur d'appel de fonction
correspond au jeu de parenthèses suivant l'identificateur de fonction. L'opérateur d'évaluation-
séquentielle (,) est assuré d'évaluer ses opérandes de gauche à droite. (Notez que l'opérateur virgule
dans un appel de fonction n'est pas le même que l'opérateur d'évaluation-séquentielle et ne fournit pas
de garantie.) Pour plus d'informations, consultez Points de séquence.
Les opérateurs logiques garantissent également l'évaluation de leurs opérandes de gauche à droite.
Toutefois, ils évaluent le plus petit nombre d'opérandes nécessaires pour déterminer le résultat de
l'expression. Cela est appelé « évaluation de court-circuit ». Ainsi, certains opérandes de
l'expression ne peuvent pas être évalués. Par exemple, dans l'expression :
x && y++
Le second opérande, y++, est évaluée uniquement si x est vrai (valeur différente de zéro). Par
conséquent, y n'est pas incrémenté si x a la valeur False (0).