![]() |
|
![]() |
Reprenons la classe Point :
using namespace std;
class Point
{
private:
double X;
double Y;
public:
Point(double m, double n)
{
X=m;
Y=n;
cout«constructeur du Point«endl;
}
~Point(){cout«destructeur du Point«X«,«Y«endl;}
};
Point P2(2.,2.);
Imaginer que souhaitions savoir combien de points ont été crées. Nous allons prendre un 3ème attribut de Point, Compteur. Pour que cet attribut soit commun à tous les objets Point, il faut le déclarer en static :
using namespace std;
class Point
{
private:
static int Compteur;
double X;
double Y;
public:
Point(double m, double n)
{
X=m;
Y=n;
Compteur++;
cout«constructeur du «Compteur«eme Point«endl;
}
~Point()
{
cout«destructeur du Point«X«,«Y«endl;
Compteur--;
cout«il reste «Compteur« Point(s)«endl;
}
};
int Point::Compteur=0;
![]() | |
![]() |
Reprenons encore la classe Point :
using namespace std;
class Point
{
private:
double X;
double Y;
public:
Point(double m, double n){X=m;Y=n;}
void SetX(double n){X=n;}
void SetY(double n){Y=n;}
double GetX(){return X;}
double GetY(){return Y;}
void Print(){cout«Point en «X«,«Y«endl;}
};
double GetY() const {return Y;}
void Print() const {cout«Point en «X«,«Y«endl;}
P1.Print();
cout«P2.GetY()«endl;
P2.Print();
Nous avons abordé la surdéfinition des fonctions (ou méthodes de classes) dans La surdéfinition des fonctions. Nous avons vu la surdéfinition des opérateurs dans le paragraphe sur la surdéfinition et dans le chapitre sur l'amitié. Voyons encore quelques exemples qui sont souvent utiles en les illustrant par la classe Vecteur dont voici la définition :
{
int Size;
double *X;
public:
Vecteur();
Vecteur(int n, double *v);
int GetSize(){return Size;}
};
Vecteur::Vecteur()
{
Size=0;
X=0;
}
Vecteur::Vecteur(int n, double *v)
{
Size=n;
X=new double[Size];
for(int i=0 ; i<Size ; i++) X[i]=v[i];
}
Lors de la définition de la classe Vecteur pour un vecteur de taille constante nous avons écrit quelque chose du type Vecteur V=U où U est un Vecteur. La classe Vecteur que nous avions écrite ne faisait pas d'allocation dynamique et chaque attribut du vecteur U était automatiquement recopié dans les attributs de V. Si nous faisions la même chose sur notre nouvelle classe Vecteur (qui possède un pointeur ``dynamique'') voilà ce qui se passerait pour l'attribut X
en supposant que U soit un vecteur de R3. En fait, nous voudrions obtenir quelque chose comme
Pour ce faire, nous devons écrire explicitement le constructeur de recopie. Il faut donc rajouter au prototype de la classe :
{
Size=U.Size;
X= new double[Size];
for(int i=0; i<Size;i++) X[i]=U.X[i];
}
Pour les mêmes raisons, une instruction du type V=U qui ne pose pas de problème dans le cas où tous les attributs ne sont pas des pointeurs dynamiques, doit faire l'objet d'une redéfinition de l'opérateur = pour ne pas conduire aux mêmes problèmes que précédemment. Le prototype de l'opérateur = sera donc (dans la classe Vecteur)
{
if(this!=&U)
{
delete X;
Size=U.Size;
X=new double[Size];
for(int i=0; i<Size;i++) X[i]=U.X[i];
}
return *this;
}
![]() | |
![]() | |
![]() |
Il peut être pratique d'accéder à une composante d'un Vecteur V en la syntaxe suivante : V[i]. Pour cela il suffit de surdéfinir l'opérateur [] en ajoutant le prototype suivant
{
if(i<Size) return X[i];
else
{
cout«Index>Size«endl;
}
return 0;
}
![]() |
Il peut être pratique de pouvoir utiliser les méthodes cout et cin pour afficher ou entrer un Vecteur. Ces méthodes appartiennent à aux classes ostream et istream. Comme le premier argument de « ou » sera un flot (cout ou cin), les opérateurs « et » doivent être surdéfinis avec un lien d'amitié. Voici le code à rajouter au prototype de la classe.
friend istream & operator»(istream & entree, Vecteur &U);
{
sortie«(;
for(int i=0 ; i< U.Size-1 ; i++ ) sortie«U.X[i]«,;
sortie«U.X[U.Size-1]«);
return sortie;
}
istream & operator»(istream & entree, Vecteur &U)
{
if(!U.Size)
{
cout«taille du vecteur : «flush ;
entree»U.Size;
U.X = new double[U.Size];
}
cout«Entrer les «U.Size« composantes :«endl
for(int i=0 ; i< U.Size ; i++ ) entree»U.X[i];
return entree;
}
![]() | |
![]() |
L'héritage est un outils très puissant pour la réalisation et l'utilisation des classes. Nous présenterons ici que les notions de bases sur l'héritage.
Considérons un objet de la classe A ayant un certain nombre d'attributs et de méthodes ; maintenant, supposons que nous ayons un objet semblable à la classe A mais avec de petites différences (des particularités ou des compléments). On construira alors la classe B comme la classe dérivée de la classe A (A sera la classe de base). En faisant ceci, tous les attributs et les méthodes de A seront attributs et méthodes de B.
Reprenons l'exemple de la classe Point déjà utilisé :
{
private:
double X;
double Y;
public:
Point(double m, double n);
void Print();
};
Point::Point(double m, double n)
{
X=m;
Y=n;
cout«Constructeur de Point«endl;
}
void Point::Print()
{
cout«Point::Print : («X«,«Y«)«endl;
}
{
int Color;
public:
PointCol(double x, double y,int c);
void Print();
};
PointCol::PointCol(double x, double y,int c) :Point(x,y)
{
Color=c;
cout«Constructeur de PointCol«endl;
}
void PointCol::Print()
{
cout«PointCol::Print :«endl;
Point::Print();
cout«la couleur est «Color«endl;
}
{
cout«---------- Point P1 -----------«endl;
Point P1(1.5,2.);
P1.Print();
cout«---------- PointCol P2 --------«endl;
PointCol P2(2.1,5.3,5);
P2.Print();
return 0;
}
![]() | |
![]() | |
![]() |
Reprenons l'exemple précédant en changeant le main() de la sorte
{
cout«----- Point P1 ------«endl;
Point P1(1.5,2.);
P1.Print();
cout«----- PointCol P2 ----«endl;
PointCol P2(2.1,5.3,5);
P2.Print();
cout«----- Pointeur P3 ----«endl;
Point *P3;
cout«----- P3=P1 ----«endl;
P3=&P1;
P3->Print();
P3=&P2;
P3->Print();
return 0;
}
![]() |
Faîtes-le et regardez le changement.
Quelle est la raison de ce changement ? Sans entrer dans les détails, dans le cas général, c'est le compilateur qui décide d'appeler telle méthode de telle classe. Par contre, lorsque que l'on met virtual , ce choix n'est pas fait par le compilateur, mais à l'exécution (on parle de typage dynamique ).
cette partie est en cours d'élaboration....patience
Imaginons que nous voulions écrire une fonction Min qui renvoie le minimum de 2 entiers ; nous écrirons,
{
if (a<b) return a;
else return b;
}
{
if (a<b) return a;
else return b;
}
{
int a=3,b=5;
float x=4.7, y=2.1;
double u=2.5,v=3.1;
cout«le min de («a«,«b«) est «Min(a,b)«endl;
cout«le min de («x«,«y«) est «Min(x,y)«endl;
cout«le min de («u«,«v«) est «Min(u,v)«endl;
}
![]() | |
![]() | |
![]() |
{
U z;
T *y=new T[10];
...
return 0;
}
Dans cet exemple MyFunction est de type int , elle admet 3 arguments (un de type T , un de type U et un pointeur sur un type T ).
Cette notion de patron peut s'étendre aux classes. Reprenons la classe Point (encore!!!)
{
private:
double X;
double Y;
public:
Point(double m, double n);
void Print();
};
Point::Point(double m, double n)
{
X=m;
Y=n;
}
void Point::Print()
{
cout«Point::Print : («X«,«Y«)«endl;
}
{
private:
T X;
T Y;
public:
Point(T m, T n);
void Print();
};
template <class T> Point<T>::Point(T m, T n)
{
X=m;
Y=n;
}
template <class T> void Point<T>::Print()
{
cout«Point::Print : («X«,«Y«)«endl;
}
int main()
{
Point<int> P(3,5);
Point<double> P1(3.1,5.1);
Point<float> P2(4.9,8.1);
P.Print();
P1.Print();
P2.Print();
}
![]() | |
![]() | |
![]() |
This document was generated using the LaTeX2HTML translator Version 2021 (Released January 1, 2021)
The command line arguments were:
latex2html -split 1 -html_version 3.2,math -no_navigation classeII.tex
The translation was initiated on 2025-03-11