#include <stdlib.h>
#include util.h
int main()
{
int i=doubler(3);
double x = tripler(0.0);//etc...
}
#ifndef UTIL_H
#define UTIL_H
void doubler(int);
void tripler(float);
#endif
#include util.h
//ici des utilitaires et
//fonctions utiliss par main()
void tripler(int y)
{
cout<<endl<<3*y;
y=3*y;
};
double doubler(float x)
{
x*=2;
};
. Compilation
$ g++ -c main.cxx util.cxx
. Edition des liens (link)
$ g++ main.o util.o -o mon_prog
. Raccourci : compilation + dition des liens
$ g++ main.cxx util.cxx -o mon_prog
1
Janvier 2010
C++
Pierre Puiseux
class Etudiant
{
private :
char nom_[20];
int age_;
float note_exam_,note_partiel_,note_finale_;
public : //methodes et donnees publiques
float rien;
9
10
11
12
13
UPPA
LMA
Janvier 2010
15
UPPA
Pierre Puiseux
float noteFinale(void)
{return note_finale_;}
14
16
C++
};
LMA
Janvier 2010
C++
Pierre Puiseux
UPPA
Etudiant *a;
a = new Etudiant();
...
delete() a;
LMA
Janvier 2010
C++
Pierre Puiseux
1.4. Allocation dynamique. Loprateur new() permet dallouer dynamiquement lespace mmoire ncessaire pour une (ou plusieurs) instance(s) de classe donne, de la mme manire que
pour les types standard :
. Etudiant* pe=new Etudiant; pour un seul exemplaire
. Etudiant* pe=new Etudiant[10]; pour un tableau de 10 tudiants.
La dsallocation se fait par loprateur delete ou delete[]
1.5. Accs aux membres. Soit e une instance de classe Etudiant dclare par
. Etudiant e;
1.5.1. Loprateur ".". Permet un accs direct aux attributs ou mthodes de linstance :
. cout <<e.nom; accs lattribut nom
. e.calculNoteFinale(); excution de la mthode calculNoteFinale
1.5.2. Loprateur "->". Permet laccs aux aux attributs ou mthodes de linstance via un pointeur. Par exemple, si un pe est un pointeur sur Etudiant,
. Etudiant* pe = &e;
alors on accde aux membres de e par pe->xxx qui quivaut e.xxx ou encore (*pe).xxx :
. cout <<pe->nom;
. pe->calculNoteFinale();
UPPA
LMA
Janvier 2010
C++
Pierre Puiseux
class Toto
{
private : float x_;
public : void faireQuelqueChose(void);
};
. fichier toto.cxx
1
2
3
4
5
6
UPPA
#include "toto.h"
void Toto::faireQuelqueChose(void)
{
cout << endl
<<"d'accord";
}
LMA
Janvier 2010
C++
Pierre Puiseux
1.7. Le pointeur this this. Permet un objet daccder ses propres membres.
Dans une mthode, il est frquent que lobjet lui-mme fasse un accs ses propres membres.
Dans ce cas on a une notation simplifie : on crit le membre tout seul, sans expliciter lobjet en
question. Cest ce que nous avons fait dans les fonctions de la classe Etudiant :
1
2
3
4
5
6
7
8
9
10
class Etudiant
{
...
void details() const
{
cout << nom_ <<";"<< age_
<< " ans ; Examen :"<< note_exam_
<< " partiel: " << note_partiel_;
}
...
};
Il arrive que dans une mthode il soit ncessaire de faire rfrence lobjet (tout entier) travers
lequel la mthode est appele. On dispose pour cela de la variable this qui est un pointeur vers
lobjet en question. Par exemple, la mthode Etudiant::details() peut scrire de manire
quivalente :
1
2
3
4
5
6
7
8
9
10
class Etudiant
{
...
void details() const
{
cout << this->nom_ <<";"<< this->age_
<< " ans ; Examen :"<< this->note_exam_
<< " partiel: " << this->note_partiel_;
}
...
};
Tout se passe comme si this tait pass la mthode comme un argument cach... ce qui est
effectivement le cas.
En ralit, les classes C++ sont des objets C dguis de la manire suivante : si a=A(); est
une instance de type A, et b(); est une mthode de A, alors un appel a.b(); est traduit par le
prcompilateur en un appel A::b(a);. Linstance a est largument fantme de la mthode A::b().
En C++ cet argument reste fantme tandis que dans dautres langages, il est explicitement pass
comme argument de la mthode. En Python , par exemple, une mthode b() de la classe A se
dclare
def b(self):...
o self est lquivalent Python du this de C++ .
Dans certaines bibliothques C++ , le pointeur lthis est explicitement indiqu, pour toute utilisation des mthodes et attributs de la classe, comme dans la classe Etudiant ci-dessus.
UPPA
LMA
Janvier 2010
C++
Pierre Puiseux
class Point {
public:
void afficher()
{cout << '(' << x_ << ',' << y_ << ')';}
void move(int a, int b)
{x_ = a; y_ = b;}
double distance(const Point& autrePoint)
{
int dx = x_ - autrePoint.x_;
int dy = y_ - autrePoint.y_;
return sqrt(dx*dx + dy*dy);
}
private:
int x_, y_;
};
Lors dun appel tel que p.distance(q) lobjet p accde aux membres privs x_ et y_ de lobjet
q. On dit que C++ pratique lencapsulation au niveau de la classe, non au niveau de lobjet.
UPPA
LMA
Janvier 2010
C++
Pierre Puiseux
1.9. Constructeurs. Un constructeur dune classe est une mthode spciale qui :
. a le mme nom que la classe,
. nindique pas de type de retour,
. ne contient pas dinstruction return.
Le rle dun constructeur est dinitialiser un objet, notamment en donnant des valeurs ses attributs.
Le constructeur na pas soccuper de trouver lespace pour lobjet ; il est appel (immdiatement) aprs que cet espace ait t obtenu, et cela quelle que soit la sorte dallocation qui a t faite :
statique, automatique ou dynamique, cela ne regarde pas le constructeur. Exemple :
1
2
3
4
5
6
7
8
class Point {
private:
int x_, y_;
public:
Point(int a, int b)//constructeur
{ x_ = a; y_ = b; }
... autres methodes ...
};
class Point {
private:
int x_, y_;
public: //3 constructeurs
Point(int a, int b)
{ x_ = a; y_ = b; }
Point(int a)
{ x_ = a; y_ = 0; }
Point(void)
{ x_ = y_ = 0; }
... autres methodes ...
};
Lemploi de paramtres avec des valeurs par dfaut permet de grouper des constructeurs. La classe
suivante possde les mmes constructeurs que la prcdente :
UPPA
LMA
Janvier 2010
1
2
3
C++
Pierre Puiseux
class Point {
private:
int x_, y_;
4
5
6
7
8
9
public:
Point(int a = 0, int b = 0)
{x_ = a; y_ = b; }
... autres methodes ...
};
Comme les autres mthodes, les constructeurs sont en gnral dclars (prototyps) dans la classe
et implments ailleurs. Ainsi, la classe prcdente pourrait scrire galement
. dans le fichier point2d.h :
1
2
3
4
5
6
7
class Point {
private:
int x_, y_;
public:
Point(int a = 0, int b = 0)
...
};
UPPA
#include "point2d.h"
Point::Point(int a, int b)
{x_ = a; y_ = b; }
10
LMA
Janvier 2010
C++
Pierre Puiseux
class Etudiant
{
private :
const string nom_;
float note_exam_,note_partiel_;
public :
Etudiant(nom, float NE, float NP):nom_(nom)
{note_exam_=NE;note_partiel=NP;}
float NoteFinale(void)
{return 0.5*(note_exam_+note_partiel_);
const float NoteExam(void)
{return note_exam_;}
float& NoteExam(void)
{return note_exam_;}
};
1.10.2. Mthodes constantes. Le mot const plac la fin de len-tte dune mthode indique que
ltat de lobjet travers lequel la fonction est appele nest pas chang du fait de lappel. Cest
une manire de dclarer quil sagit dune mthode de consultation de lobjet, non dune mthode
de modification :
1
2
3
4
5
6
class Point
{
...
void move(int a, int b);
// modifie l'objet
float distance(Point p) const; // ne modifie pas l'objet
...
};
A lintrieur dune mthode const dune classe C le pointeur this est de type const C *
const (pointeur constant vers un C constant) : lobjet point par this ne pourra pas tre modifi.
Cela permet au compilateur dautoriser certains accs qui, sans cela, auraient t interdits. Par
exemple, examinons la situation suivante :
1
2
UPPA
11
LMA
C++
Janvier 2010
Pierre Puiseux
la qualification const de la mthode distance est indispensable pour que lexpression prcdente
soit accepte par le compilateur. Cest elle seule, en effet, qui garantit que le Point a, contraint
rester constant, ne sera pas modifi par lappel de la mthode distance().
De mme que pour les arguments dune fonction,
il est conseill de qualifier const toute mthode qui peut ltre.
1.10.3. Coexistence des mthodes constantes et non constantes. La qualification const dune mthode
fait partie de sa signature. Ainsi, on peut surcharger une mthode non constante par une mthode
constante ayant, part cela, le mme en-tte. La mthode non constante sera appele sur les objets
non constants, la mthode constante sur les objets constants.
On peut utiliser cette proprit pour crire des mthodes qui neffectuent pas le mme traitement ou qui ne rendent pas le mme type de rsultat lorsquelles sont appeles sur un objet constant et lorsquelles sont appeles sur un objet non constant. Exemple (se rappeler que le rsultat
renvoy par une mthode ne fait pas partie de sa signature) :
1
2
3
4
5
6
7
8
9
class Point {
int x, y;
public:
int X() const { return x; }
int Y() const { return y; }
int& X() { return x; }
int& Y() { return y; }
...
};
Avec la dclaration prcdente, les mthodes X et Y sont scurises : sur un objet constant elles
ne permettent que la consultation, sur un objet non constant elles permettent la consultation et la
modification :
1
2
3
4
5
6
7
8
UPPA
3);
Oui
ERREUR ( a.X() rend une valeur)
Oui
// Oui ( b.X() rend une rfrence)
12
LMA
C++
Janvier 2010
Pierre Puiseux
1.11. Exercices.
Exercise 1. Algorithme dEuclide
Prototypez, implmentez et tester une fonction qui calcule le pgcd de deux entiers suivant lalgorithme dEuclide :
PGCD(a, b)
Si b=0
alors PGCD=a
Sinon
r = a%b //egal au reste de la division entire (modulo) de a par b
PGCD=PGCD(b, r)
Ce qui pourrait donner en C :
1
2
3
4
Exercise 2. Une classe Fraction. On se propose de programmer une classe dont les instances
se comportent autant que possible comme les fractions de Q. Le numrateur et le dnominateur
doivent tre entiers.
(1) Dterminer la structure de donnes idoine.
(2) Constructeur principal :
(a) Ecrire le prototype (dans fraction.h) du constructeur qui doit permettre dinstancier
une Fraction par linstruction :
. Fraction x(1,2);
(b) Ecrire la dfinition du constructeur (dans le fichier fraction.cxx). On prvoira un
arrt du programme si le dnominateur est nul (linstruction assert(cond); stoppe
le programme si cond a une valeur boolenne fausse).
(c) Ecrire un programme principal, dans fraction.cxx, qui teste ce constructeur.
(3) Autres constructeurs :
(a) prototypez les constructeurs (fichier fraction.h) qui permettent dinstancier des
fractions ainsi :
1
2
3
13
LMA
Janvier 2010
C++
Pierre Puiseux
1
2
3
4
5
6
#include <fstream>
#include <iostream>
using namespace std;
int PGCD(const int, const int);
class Fraction
{
public:
int n_,d_;
Fraction(int a=0, int b=1);
Fraction(const char*);
Fraction(const Fraction&);
void setNumerateur(const int& a);
int numerateur(void);
void reduire(void);
Fraction reduite(void);
void ecrire(ostream& out) ;
};
#include <fstream>
#include <iostream>
#include <iomanip>
#include <assert.h>
#include "fraction0.h"
using namespace std;
7
8
9
10
11
12
13
14
UPPA
LMA
Janvier 2010
15
16
17
18
C++
Pierre Puiseux
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void Fraction::reduire(void)
{
int pgcd = PGCD(n_, d_);
n_ /= pgcd;
d_ /= pgcd;
}
Fraction Fraction::reduite(void)
{
Fraction w(n_,d_);
w.reduire();
return w;
}
void Fraction::ecrire(ostream& out)
{
int n(n_), ln(0);
while (n!=0) {n/=10;ln++;}
int d(d_), ld(0);
while (d!=0) {d/=10;ld++;}
int l = max(ln,ld);
int m = (ln+ld)/2;
cout << setw(max(m,ln)) << n_ << endl;
if (d_==1) return;
for (int i=0; i<l;i++)
out<< "-";
out << endl << setw(max(m,ld)) << d_;
}
int main()
{
Fraction X(100,50); X.ecrire(cout);cout << endl;
X.reduire();
X.ecrire(cout);cout << endl;
Fraction Y(X.reduite());Y.ecrire(cout);cout << endl;
}
15
LMA
Janvier 2010
C++
Pierre Puiseux
(a) une mthode reel() qui renvoit la valeur relle sous forme dun double,
(b) une mthode mult(f) qui ne modifie pas la Fraction elle-mme, qui renvoit le
produit de la fraction elle-mme par la Fraction f.
(c) Une version fonction de la mthode mult qui permette dcrire Fraction f1(1,2)
,f2(3,4),f=mult(f1,f2);
(4) Solution :09-classes/fraction1.h et 09-classes/fraction1.cxx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
#include <fstream>
#include <iostream>
using namespace std;
class Fraction
{
private:
int n_,d_;
public:
Fraction(int a=0, int b=1);
Fraction(const char*);
Fraction(const Fraction&);
void setNumerateur(const int& a);
int numerateur(void) const;
void reduire(void);
Fraction reduite(void) const;
void ecrire(ostream& out) const;
double reel(void) const;
Fraction mult(const Fraction&) const;
};
Fraction mult(const Fraction&, const Fraction&);
int PGCD(const int, const int);
#include <fstream>
#include <iostream>
#include <iomanip>
#include <assert.h>
#include "fraction1.h"
using namespace std;
int PGCD(const int a, const int b)
{return b ? PGCD(b,a%b):a;}
9
10
11
12
13
14
15
16
UPPA
LMA
Janvier 2010
17
18
19
20
21
22
23
C++
Pierre Puiseux
{return n_;}
void Fraction::reduire(void)
{
int pgcd = PGCD(n_,d_);
n_ /= pgcd;
d_ /= pgcd;
}
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
UPPA
17
LMA
Janvier 2010
Pierre Puiseux
Z.ecrire(cout);
f1(1,2),f2(3,4),W=mult(f1,f2);
W.ecrire(cout);cout << endl;
W.reduite().ecrire(cout);
cout << endl ;
W.ecrire(cout);
63
64
65
66
67
68
69
C++
#include <fstream>
#include <iostream>
using namespace std;
class Fraction
{
private:
int n_,d_;
public:
Fraction(int a=0, int b=1);
Fraction(const char*);
Fraction(const Fraction&);
void setNumerateur(const int& a);
int numerateur(void) const;
void reduire(void);
Fraction reduite(void) const;
void ecrire(ostream& out) const;
void lire(istream& in);
double reel(void) const;
Fraction mult(const Fraction&) const;
Fraction add(const Fraction&) const;
};
Fraction mult(const Fraction&, const Fraction&);
Fraction add(const Fraction&, const Fraction&);
1Au paragraphe suivant, nous amliorerons ces mthodes pour les rendre plus commode utiliser.
UPPA
18
LMA
Janvier 2010
24
1
2
3
4
5
6
7
8
C++
Pierre Puiseux
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
UPPA
LMA
Janvier 2010
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
C++
Pierre Puiseux
}
void Fraction::lire(istream& in)
{in >> n_ >> d_;}
//version methode
Fraction Fraction::mult(const Fraction& f) const
{return Fraction(n_*f.n_, d_*f.d_);}
//Version fonction
Fraction mult(const Fraction& z1, const Fraction& z2)
{return z1.mult(z2);}
//version methode
Fraction Fraction::add(const Fraction& f) const
{return Fraction(n_*f.d_+ d_*f.n_,d_*f.d_);}
//Version fonction
Fraction add(const Fraction& z1, const Fraction& z2)
{return z1.add(z2);}
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
UPPA
int main()
{
Fraction X(100,50);
X.ecrire(cout);
X.reduire();
cout << endl;
X.ecrire(cout);
Fraction Y(50,3);
Fraction Z=X.mult(Y);
Z.reduire();
cout << endl;
Z.ecrire(cout);
Fraction W=mult(X,Y);
cout << endl;
W.ecrire(cout);
cout << endl ;
W.reduite().ecrire(cout);
cout << endl ;
W.ecrire(cout);
cout <<endl<< PGCD(60,36);
ifstream fin ("fraction.txt");
W.lire(fin);
cout << endl;
W.ecrire(cout);
X=Fraction(2,3);
Y=Fraction(7,8);
W=add(X,Y);
cout << endl;
W.ecrire(cout);
20
LMA
Janvier 2010
C++
Pierre Puiseux
91
92
UPPA
21
LMA
C++
Janvier 2010
Pierre Puiseux
1.12. Surcharge des oprateurs internes. Une premire mthode pour surcharger les oprateurs
consiste les considrer comme des mthodes normales de la classe sur laquelle ils sappliquent.
Le nom de ces mthodes est donn par le mot-cl operator, suivi de loprateur surcharger. Le
type de la fonction de loprateur est le type du rsultat donn par lopration, et les paramtres,
donns entre parenthses, sont les oprandes.
Les oprateurs de ce type sont appels oprateurs internes, parce quils sont dclars lintrieur de la classe.
Voici la syntaxe :
type operatorOp(paramtres)
A + B est traduite par le compilateur par : A.operator+(B)
A * B est traduite par le compilateur par : A.operator*(B)
etc...
A Op B est traduite par le compilateur par : A.operator Op(B)
Avec cette syntaxe, le premier oprande est toujours lobjet auquel cette fonction sapplique.
Cette manire de surcharger les oprateurs est donc particulirement bien adapte pour les oprateurs qui modifient lobjet sur lequel ils travaillent, comme par exemple les oprateurs =, +=, ++,
etc. Les paramtres de la fonction oprateur sont alors le deuxime oprande. Les oprateurs dfinis en interne renvoient souvent lobjet sur lequel ils travaillent (ce nest pas une ncessit cependant). Cela est faisable grce au pointeur this, qui est un pointeur sur lobjet lui-mme. Voici
quelques oprateurs possibles pour la classe Point2D :
1
2
3
4
5
6
7
8
9
10
UPPA
22
LMA
Janvier 2010
C++
Pierre Puiseux
1.13. Surcharge des oprateurs externes. Une deuxime possibilit nous est offerte par le langage
pour surcharger les oprateurs. La dfinition de loprateur ne se fait plus dans la classe qui lutilise, mais en dehors de celle-ci, par surcharge dun oprateur de lespace de nommage global. Il
sagit donc doprateurs externes cette fois. Dans ce cas, tous les oprandes de loprateur devront
tre passs en paramtres : il ny aura pas de paramtre implicite.
La syntaxe est la suivante :
type operatorOp(oprandes)
o oprandes est la liste complte des oprandes.
Lavantage de cette syntaxe est que loprateur est rellement symtrique, contrairement ce
qui se passe pour les oprateurs dfinis lintrieur de la classe. Les oprateurs externes doivent
tre dclars comme tant des fonctions amies (friend) de la classe sur laquelle ils travaillent, faute
de quoi ils ne pourraient pas manipuler les attributs de leurs oprandes. Les oprateurs de lecture
ou dcriture sont dfinis comme oprateurs externes. En guise dexemple on rajoute dans la classe
Point2D un oprateur dcriture :
Fichier Point2D.h :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
UPPA
class Point2D {
double x,y;
public:
Point2D(){}
Point2D(double a, double b)
{x=a; y=b;}
~Point2D(){}
double Distance() const
double Distance(const Point2D& p) const
double & GetX(){return x;}
const double & GetX() const
{return x;}
double & GetY(){return x;}
const double & GetY() const
{return x;}
Point2D & operator+=(const Point2D & p)
{x=x+p.x;y=y+p.y; return *this;}
Point2D & operator-=(const Point2D & p)
{x=x-p.x; y=y-p.y; return *this;}
Point2D & operator*=(double v)
{x=x*v; y= y*v; return *this;}
double operator*(const Point2D & p)
{return x*p.x+y*p.y;}
Point2D & operator=(const Point2D & p)
{ x = p.x; y=p.y; return *this; }
friend ostream & operator << (ostream & os, const Point2D
& p);
};
23
LMA
Janvier 2010
C++
Pierre Puiseux
Fichier Point2D.Cxx :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "Point.h"
#include <math.h>
/*--------------------------------------*/
double Point2D::Distance() const
{return sqrt(x*x+y*y));}
/*--------------------------------------*/
double Point2D::Distance (const Point2D & p) const
{return sqrt(pow(p.x-x,2.)+pow(p.y-y,2.));}
/*---------------------------------------*/
ostream & operator << (ostream & os, const Point2D & p)
{
os <<"(x,y)=("<<x<<","<<y<<")";
return os;
}
Ici loprateur dcriture renvoie la rfrence de lobjet os de manire pouvoir, enchainer les
commandes dcriture. On peut donc crire
cout<<p1<<p2;
Si p1 et p2 sont deux objets de type Point2D.
UPPA
24
LMA
Janvier 2010
C++
Pierre Puiseux
class A
{
int a; // Une donnee privee.
friend void ecrit_a(int i); // Une fonction amie.
};
A essai;
void ecrit_a(int i)
{
essai.a=i; // Initialise a.
return;
}
1.15. Exercices.
Exercise 6. Classe Fraction : surcharges doprateurs. On partira de la version fraction2.cxx et
fraction2.h
(1) Surchargez loprateur + comme oprateur-mthode de la classe (Pour viter de rcrire tout
loprateur, on rutilisera la fonction add ou la mthode Fraction::add dj dfinis.
(2) Surcharger loprateur * comme oprateur externe la classe (mme remarque concernant
la rutilisation des fonctions et de mthodes dja crites.)
(3) Ecrire les deux oprateurs dinsertion et dextraction de la classe Fraction. Testez ensuite
les instructions :
1
2
3
Fraction z(1,2),z1(2,3);
cout << z << endl << z1;
cin >> z;
25
LMA
Janvier 2010
C++
Pierre Puiseux
(2) Ecrire une mthode Fraction::inverser(...) qui inverse in-situ une fraction.
(3) Ecrire une fonction inverse(...) qui renvoit linverse dune fraction, sans modifier la
fraction elle-mme.
(4) Un oprateur-fonction unaire : operator-(...) qui renvoit loppos dune fraction, sans
modifier la fraction elle-mme.
(5) Un oprateur-fonction binaire operator-(...) qui calcule et renvoit la diffrence de
deux fractions sans les modifier.
(6) Un oprateur-mthode operator+=(...) qui permette dcrire Fraction f(1,2),f1
(2,3);f+=f1;. Pour cet oprateur, on ne cherchera pas utiliser les fonctions ou mthodes dj crites.
(7) Rcrire loprateur-fonction operator+(...) (et la fonction add(...)) en utilisant
loprateur-mthode +=.
(8) Corrig : voir fraction4.cxx et fraction4.h.
UPPA
26
LMA