Académique Documents
Professionnel Documents
Culture Documents
Programmation Orientée Objet & Autres Concepts Illustrés en C++11 Et en Java
Programmation Orientée Objet & Autres Concepts Illustrés en C++11 Et en Java
orientée objet
& autres concepts
illustrés en C++11 et en Java
Eric Lecolinet - Télécom ParisTech
http://www.telecom-paristech.fr/~elc
24 Septembre 2019
Dans ce cours
Organisation du cours
– présentation des langages informatique par Patrick Bellot
– ce qui est similaire à Java (révision...)
– ce qui est différent de Java
– interfaces graphiques Java Swing
Liens
– http://www.telecom-paristech.fr/~elc/
– http://www.telecom-paristech.fr/~elc/inf224/
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 2
Brève historique (très parcellaire)
1972 : Langage C
AT&T Bell Labs
Java
– à l'origine : simplification du C++
– beaucoup de ressemblances mais aussi des différences importantes
Compilation
– Java : code source compilé (byte code) puis interprété (ou compilé à la volée)
– C/C++ : compilé en code natif
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 4
Références et liens
Livres, tutoriaux, manuels
– Le langage C++, Bjarne Stroustrup (auteur du C++), Pearson
son site : http://www.stroustrup.com
– manuel de référence : http://cppreference.com ou www.cplusplus.com/reference
– faqs, aide : https://isocpp.org/faq, https://stackoverflow.com, etc.
– Cours C++ de Christian Casteyde : http://casteyde.christian.free.fr/
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 5
Premier chapitre :
Programme, classes, objets
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 6
Programme C++
Constitué
– de classes comme en Java
– et, éventuellement, de fonctions et variables « non-membre » (= hors classes)
comme en C
Car.cpp Truck.cpp
#include "Car.h"! #include "Truck.h"!
! !
void Car::start() {! void Truck::start(){!
....! ....!
}! }!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 7
Déclarations et définitions
C/C++ : deux types de fichiers
– déclarations dans fichiers header (extension .h ou .hpp ou pas d'extension)
– définitions dans fichiers d’implémentation (.cpp)
– en général à chaque .h correspond un .cpp
myprog.cpp Truck.cpp
Car.cpp
#include "Car.h"! #include "Car.h"! #include "Truck.h"!
#include "Truck.h"! ! !
! void Car::start() {! void Truck::start(){!
int main() {! ....! ....!
....! }! }!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 8
Compilation et édition de liens
myprog.cpp Car.cpp Truck.cpp
#include "Car.h"! #include "Car.h"! #include "Truck.h"!
#include "Truck.h"! ! !
! void Car::start() {! void Truck::start(){!
int main() {! ....! ....!
....! }! }!
!
Compilation
Bibliothèques
myprog.o Car.o Truck.o binaires !
contenant les
Editions de liens classes et
fonctions
myprog standard !
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 9
Déclaration de classe
Dans le header Circle.h :
class Circle {!
private:!
int x = 0, y = 0; ! variables d'instance!
!
unsigned int radius = 0;!
public:!
Circle(int x, int y, unsigned int radius);! constructeur!
!
Remarques
– même sémantique que Java (à part const)
– il faut un ; après la }
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 10
Variables d'instance
class Circle {!
private:!
int x = 0, y = 0; ! variables d'instance!
unsigned int radius = 0;!
!
public:!
Circle(int x, int y, unsigned int radius);!
void setRadius(unsigned int)!
unsigned int getRadius() const;!
unsigned int getArea() const;!
....!
}; !
Variables d’instance
– chaque objet possède sa propre copie de la variable
– normalement private ou protected (à suivre)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 11
Constructeurs
class Circle {!
private:!
int x = 0, y = 0; !
unsigned int radius = 0;!
!
public:!
Circle(int x, int y, unsigned int radius);! constructeur!
void setRadius(unsigned int)!
unsigned int getRadius() const;!
unsigned int getArea() const;!
....!
}; !
Les constructeurs
– sont appelés quand les objets sont créés afin de les initialiser
– sont toujours chaînés :
• les constructeurs des superclasses sont exécutés dans l'ordre descendant
• pareil en Java (et pour tous les langages à objets)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 12
Méthodes d'instance
class Circle {!
private:!
int x = 0, y = 0; !
unsigned int radius = 0;!
!
public:!
Circle(int x, int y, unsigned int radius);!
void setRadius(unsigned int)!
unsigned int getRadius() const;! méthodes d'instance!
unsigned int getArea() const;!
....!
}; !
Remarques
– généralement public
– méthodes const : ne modifient pas les variables d'instance (n'existent pas en Java)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 13
Définition des méthodes class Circle {!
Header Circle.h
private:!
int x, y; !
Dans le fichier d’implémentation unsigned int radius;!
Circle.cpp : public:!
Circle(int x, int y, unsigned int radius);!
void setRadius(unsigned int); !
#include "Circle.h" ! unsigned int getRadius() const;!
unsigned int getArea() const;!
! ....!
Circle::Circle(int _x, int _y, unsigned int _r) {! };
x = _x;!
y = _y; !
radius = _r;! insère le contenu de Circle.h!
}!
!
void Circle::setRadius(unsigned int r) { ! précise la classe :: typique du C++!
radius = r;!
}!
!
unsigned int Circle::getRadius() const { !
return radius;!
}!
!
unsigned int Circle::getArea() const {!
return 3.1416 * radius * radius;!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 14
Définitions dans les headers
Dans le header Circle.h
class Circle {!
private:!
int x = 0, y = 0; !
unsigned int radius = 0;!
!
public:!
void setRadius(unsigned int r) {radius = r;}! méthodes inline!
unsigned int getRadius() const {return radius;}!
....!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 16
Instanciation
Dans un autre fichier .cpp :
pointeur c
#include "Circle.h"! 0xf12a4321
0xf12a4321
!
int main() {! instance
de Circle
Circle * c = new Circle(0, 0, 50);!
....! contient l'adresse !
}! de l'instance!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 17
Pointeurs C/C++ vs. références Java
pointeur c
C++ Circle * c = new Circle(0, 0, 50);! 0xf12a4321
! 0xf12a4321
instance
de Circle
Java Circle c = new Circle(0, 0, 50);! contient l'adresse !
! de l'instance!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 18
Pointeurs C/C++ vs. références Java
pointeur c
C++ Circle * c = new Circle(0, 0, 50);! 0xf12a4321
! 0xf12a4321
instance
de Circle
Java Circle c = new Circle(0, 0, 50);! contient l'adresse !
! de l'instance!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 19
Accès aux variables et méthodes d'instance
class Circle {!
void foo() {! private:!
int x, y; !
Circle * c = new Circle(0, 0, 50);!
unsigned int radius;!
c->radius = 100;! public:!
Circle(int x, int y, unsigned int radius);!
unsigned int area = c->getArea();!
void setRadius(unsigned int); !
}! unsigned int getRadius() const;!
unsigned int getArea() const;!
....!
};
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 20
Encapsulation
class Circle {!
void foo() {! private:!
int x, y; !
Circle * c = new Circle(0, 0, 50);!
unsigned int radius;!
c->radius = 100; // interdit!! public:!
Circle(int x, int y, unsigned int radius);!
unsigned int area = c->getArea();!
void setRadius(unsigned int); !
}! unsigned int getRadius() const;!
unsigned int getArea() const;!
....!
};
Problème
– radius est private => c n’a pas le droit d’y accéder
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 21
Encapsulation
class Circle {!
void foo() {! private:!
int x, y; !
Circle * c = new Circle(0, 0, 50);!
unsigned int radius;!
c->radius = 100; // interdit!! public:!
Circle(int x, int y, unsigned int radius);!
unsigned int area = c->getArea();!
void setRadius(unsigned int); !
}! unsigned int getRadius() const;!
unsigned int getArea() const;!
....!
};
Encapsulation
– séparer la spécification de l'implémentation (concept de "boîte noire")
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 22
Encapsulation
Abstraire
• exhiber les concepts
• cacher les détails d'implémentation
Modulariser
Encapsulation
– séparer la spécification de l'implémentation (concept de "boîte noire")
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 23
Encapsulation
Protéger l'intégrité de l'objet
• ne peut pas être modifié à son insu => peut assurer la validité de ses données
• il est le mieux placé pour le faire !
Modulariser
• limiter les dépendances entre composants logiciels
• pouvoir changer l'implémentation d'un objet sans modifier les autres
Encapsulation
– séparer la spécification de l'implémentation (concept de "boîte noire")
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 24
Encapsulation : droits d'accès
Droits d’accès C++
– private : pour les objets de cette classe (par défaut)
– protected : également pour les sous-classes
– public : pour tout le monde
– friend : pour certaines classes ou certaines fonctions
cette classe a
class Circle {! droit d'accès !
friend class ShapeManager;!
friend bool isInside(const Circle&, int x, int y);!
...! cette fonction a
};! droit d'accès !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 25
Accès vs. droits d'accès
Alice Bob
0xf12a4321
private:! public:!
Bob * bob; ! void hello(string s) {!
...;!
public:!
}!
void coucouBob() {!
bob->hello("coucou");!
}!
Il ne suffit pas d'avoir la clé de la porte encore faut-il savoir où elle se trouve !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 26
Retour sur
class Circle {!
private:!
les constructeurs
int x, y; !
unsigned int radius;!
public:!
Circle(int x, int y, unsigned int radius);!
....!
};
Trois formes
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 27
Destruction des objets
pointeur c
void foo() {! 0xf12a4321
0xf12a4321
Circle * c = new Circle(100, 200, 35);!
...! instance
delete c;! de Circle
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 28
Destructeur/finaliseur
class Circle {!
public:!
~Circle() {cerr << "adieu monde cruel\n";} ! destructeur!
...!
};!
!
void foo() {!
Circle * c = new Circle(100, 200, 35);!
...!
delete c; !
} !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 29
Destructeur/finaliseur
Quand faut-il un destructeur ?
– cas particuliers
• classes de base polymorphes
Drawing
(voir plus loin)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 30
Pointeurs nuls et pendants
pointeur c
0xf12a4321
0xf12a4321
instance
void bar() {! de Circle
Circle * c = new Circle(10, 20, 30);!
foo(c);!
delete c; !
!
foo(c); ! Correct ?
delete c; !
}!
!
void foo(Circle * c) {!
unsigned int area = 0;!
if (c) area = c->getArea(); !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 31
Pointeurs nuls et pendants
pointeur c
0xf12a4321
0xf12a4321
instance
void bar() {! de Circle
Circle * c = new Circle(10, 20, 30);!
foo(c);!
delete c; ! c est pendant :
! pointe sur un objet qui n'existe plus
foo(c); !
delete c; ! !! DANGER !!
}!
!
void foo(Circle * c) {! le pointé n'existe plus
unsigned int area = 0;!
if (c) area = c->getArea(); !
!! CRASH !!
else perror("Null pointer");!
aléatoire
}!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 32
Pointeurs nuls et pendants
pointeur c
0xf12a4321
0xf12a4321
instance
void bar() {! de Circle
Circle * c = new Circle(10, 20, 30);!
foo(c);!
delete c; !
pointeur c
c = nullptr; !
null
!
foo(c); !
delete c; !
}!
c est nul : pointe sur rien
!
void foo(Circle * c) {!
unsigned int area = 0;!
OK
if (c) area = c->getArea(); !
else perror("Null pointer");!
}!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 33
Initialisation des variables
Circle * c; !
!
Circle * c = nullptr; !
! Correct ?
Circle * c = new Circle; !
!
!
!
!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 34
Initialisation des variables
!
!
!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 35
Surcharge (overloading)
class Circle {!
Circle();!
Circle(int x, int y, unsigned int r); !
void setCenter(int x, int y);!
void setCenter(Point point);!
};!
Attention
– ne pas confondre avec la redéfinition de méthodes (overriding)
dans une hiérarchie de classes
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 36
Paramètres par défaut
class Circle {!
Circle(int x = 0, int y = 0, unsigned int r = 0); !
....!
};!
!
Alternative à la surcharge
– n'existe pas en Java
– les valeurs par défaut doivent être à partir de la fin
– erreur de compilation s'il y a des ambiguïtés
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 37
Variables de classe
class Circle {!
int x, y; !
unsigned int radius;!
static int count;!
public:!
variables de classe!
static const int MAX = 10;!
static constexpr double PI = 3.1415926535;!
...!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 38
Variables de classe
class Circle {!
int x, y; !
unsigned int radius;!
static int count;! doit être définie dans un .cpp!
public:!
static const int MAX = 10;!
static constexpr double PI = 3.1415926535;!
...!
};!
Bizarrerie
– les variables static doivent être définies dans un .cpp (et seulement un !)
– sauf si le type est const int ou constexpr (C+11)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 39
Méthodes de classe
class Circle {!
...!
static int count;! variable de classe!
public:!
static int getCount() {return count;}! méthode de classe !
...!
};!
!
void foo() {!
int num = Circle::getCount();! appel de la méthode de classe!
....!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 40
Namespaces
fichier math/Circle.h! fichier graph/Circle.h!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 41
Namespace par défaut
fichier math/Circle.h! fichier graph/Circle.h!
using namespace
– modifie la portée : symboles de ce namespace directement accessibles
– similaire à import en Java
– éviter d'en mettre dans les headers
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 42
Entrées / sorties standard
#include "Circle.h"!
#include <iostream>! flux d'entrées/sorties !
!
int main() {!
Circle * c = new Circle(100, 200, 35);!
std::cout !
<< "radius: " << c->getRadius() << ‘\n’ !
<< "area: " << c->getArea() !
<< std::endl;! passe à la ligne !
}! et vide le buffer!
Flux standards
std = namespace de la bibliothèque standard
std::cout console out = sortie standard
std::cerr console erreurs = sortie des erreurs (affichage immédiat)
std::cin console in = entrée standard
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 43
Fichiers
#include "Circle.h"! fichiers!
#include <iostream> !
#include <fstream>! ostream = flux de sortie!
! noter le & (à suivre) !
void foo(std::ostream & s, Circle * c) { !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 44
Buffers
#include "Circle.h"!
#include <iostream> !
#include <sstream> ! buffers de texte!
!
void foo(std::ostream & s, Circle * c) { !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 45
Retour sur les méthodes d'instance : où est la magie ?
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 46
Le this des méthodes d'instance
Le compilateur fait la transformation :
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 47
Documentation
/** @brief modélise un cercle.!
* Un cercle n'est pas un carré ni un triangle.!
*/!
class Circle {!
/// retourne la largeur.!
unsigned int getWidth() const;!
!
unsigned int getHeight() const; ///< retourne la hauteur.!
!
void setPos(int x, int y);!
/**< change la position: @see setX(), setY().!
*/!
...!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 48
Style et commentaires
/** @brief modélise un cercle.!
* Un cercle n'est pas un carré ni un triangle.!
*/!
class Circle {!
/// retourne la largeur.!
unsigned int getWidth() const;!
!
unsigned int getHeight() const; ///< retourne la hauteur.!
!
void setPos(int x, int y);!
/**< change la position: @see setX(), setY().!
*/!
...!
};!
Règles
• être cohérent
• indenter (utiliser un IDE qui le fait automatiquement : TAB ou Ctrl-I en général)
• aérer et passer à la ligne (éviter plus de 80 colonnes)
• camelCase et mettre le nom des variables (pour la doc)
• commenter quand c'est utile
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 49
Chapitre 2 : Héritage et polymorphisme
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 50
Héritage
2e Concept fondamental de l’OO Classe A
– les sous-classes héritent les méthodes et variables
class A {!
de leurs super-classes : int x;!
void foo(int);!
• la classe B a une méthode foo() et une variable x };!
– héritage simple
• une classe ne peut hériter que d'une superclasse Classe B
class B : public A {!
– héritage multiple int y;!
void bar(int);!
• une classe peut hériter de plusieurs classes };!
• C++, Python, Eiffel, Java 8 ...
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 51
Règles d'héritage Classe A
class A {!
int x;!
Constructeurs / destructeurs virtual void foo(int);!
};!
– pas hérités (mais chaînés !)
Méthodes
– héritées Classe B
class B : public A {!
– peuvent être redéfinies (overriding) int x;!
• la nouvelle méthode remplace
int y;!
celle de la superclasse void foo(int) override;!
void bar(int);!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 52
Règles d'héritage Classe A
class A {!
int x;!
virtual void foo(int);!
Variables };!
– héritées
– peuvent être surajoutées (shadowing)
Classe B
– attention : la nouvelle variable cache
class B : public A {!
celle de la superclasse :
int x;!
• B a deux variables x : x et A::x int y;!
void foo(int) override;!
– à éviter !
void bar(int);!
};!
Classe C
class C : public B {!
int z;!
void foo(int) final;!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 53
Exemple Rect
class Rect {!
...!
class Rect {! };!
protected: !
int x, y;!
unsigned int width, height;!
public:!
Square
Rect();! class Square !
...!
Rect(int x, int y, unsigned int w, unsigned int h);!
! };!
unsigned int getWidth() const;!
unsigned int getHeight() const;!
virtual void setWidth(unsigned int w);!
virtual void setHeight(unsigned int h);! Dérivation de classe:!
//...etc...! => comme extends de Java!
};!
!
Redéfinition de méthode!
class Square : public Rect { !
public: ! => override (C++11)!
Square();!
Square(int x, int y, unsigned int size);!
!
void setWidth(unsigned int w) override; !
Pourquoi faut-il
void setHeight(unsigned int h) override; !
redéfinir ces
};! deux méthodes ?
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 54
Exemple Rect
class Rect {!
...!
class Rect {! };!
protected: !
int x, y;!
unsigned int width, height;!
public:!
Square
Rect();! class Square !
...!
Rect(int x, int y, unsigned int w, unsigned int h); !
!
};!
unsigned int getWidth() const;!
unsigned int getHeight() const;!
virtual void setWidth(unsigned int w) {width = w;}!
virtual void setHeight(unsigned int h) {height = h;}!
//...etc...!
};!
!
class Square : public Rect { !
public: !
Square();!
Square(int x, int y, unsigned int size);!
!
void setWidth(unsigned int w) override {height = width = w;}! sinon ce n'est!
void setHeight(unsigned int h) override {width = height = h;}! plus un carré ! !
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 55
Chaînage des constructeurs
class Rect { !
protected: !
int x, y;!
unsigned int width, height;!
public:!
Rect() : x(0), y(0), width(0), height(0) {}!
Rect(int x, int y, unsigned int w, unsigned int h) : x(x), y(y), width(w), height(h) {}!
//...etc...!
};!
!
Chaînage implicite des constructeurs!
class Square : public Rect { !
public: !
Square() {}!
Square(int x, int y, unsigned int size) : Rect(x, y, size, size) {}!
//...etc...!
};! Chaînage explicite des constructeurs!
=> comme super() en Java!
Attention à la syntaxe :
Square(int x, int y, unsigned int size) { Rect(x, y, size, size); } FAUX !!!!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 56
Covariance des types de retour
Rect
! class Rect {!
class RectCreator {! ...!
virtual Rect* makeShape() {return new Rect;}! };!
}!
!
class SquareCreator : public RectCreator {!
Square
Square* makeShape() override {return new Square;}!
class Square !
}! ...!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 57
Inclusion des headers
Shape.h class Shape {!
...!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 58
Inclusion des headers
Shape.h class Shape {!
...!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 59
Shape.h #ifndef Graph_Shape!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 60
Directives du préprocesseur
#ifndef Truc!
Header ! #define Truc! inclut ce qui suit jusqu'à #endif !
Truc.h ! seulement si Truc n'est pas déjà défini!
class Truc {!
...! définit Truc, qui doit être unique!
};! => à forger sur nom du header !
!
#endif!
Directives de compilation
– #if / #ifdef / #ifndef pour compilation conditionnelle
– #import (au lieu de #include) empêche l'inclusion multiple (pas standard !)
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 61
Polymorphisme d'héritage
Rect
class Rect {!
3e concept fondamental de l’orienté objet ...!
};!
– le plus puissant mais pas toujours le mieux compris !
void foo() {!
Square * s = new Square(); // s voit l'objet comme un Square!
Rect * r = s; // r voit objet comme un Rect (upcasting implicite)!
...!
Square * s2 = new Rect(); // OK ? !
Square * s3 = r; // OK ? !
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 62
Buts du polymorphisme
Rect
class Rect {!
Pouvoir choisir le point de vue le plus approprié
...!
};!
selon les besoins
void foo() {!
Square * s = new Square(); // s voit l'objet comme un Square!
Rect * r = s; // r voit objet comme un Rect (upcasting implicite)!
...!
Square * s2 = new Rect(); // erreur de compilation! (downcasting interdit !)!
Square * s3 = r; // erreur de compilation!!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 63
Polymorphisme
Rect
Question à $1000 class Rect {!
...!
– quelle méthode setWidth() est appelée :
virtual void setWidth(int);!
celle du pointeur ou celle du pointé ? ...!
};!
– avec Java ?
– avec C++ ?
Square!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 64
Polymorphisme : Java
Rect
Question à $1000 class Rect {!
...!
– quelle méthode setWidth() est appelée :
virtual void setWidth(int);!
celle du pointeur ou celle du pointé ? ...!
};!
Java
– liaison dynamique / tardive : choix de la méthode à l'exécution
⇒ appelle toujours la méthode du pointé
• heureusement sinon le carré deviendrait un rectangle !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 65
Polymorphisme : C++
Rect
Question à $1000 class Rect {!
...!
– quelle méthode setWidth() est appelée :
virtual void setWidth(int);!
celle du pointeur ou celle du pointé ? ...!
};!
C++
– avec virtual : liaison dynamique / tardive => méthode du pointé comme Java
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 66
Règles à suivre Shape
class Shape {!
virtual ~Shape();!
Classe de base
virtual void setWidth(int);!
⇒ mettre virtual ...!
⇒ y compris pour les destructeurs };!
Redéfinitions Rect
⇒ mettre override ou final (C++11) class Rect : public Shape {!
~Rect();!
⇒ vérifie méthode parente
void setWidth(int) override;!
virtual ou override
...!
};!
Destructeurs virtuels
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 67
Règles à suivre Shape
class Shape {!
virtual ~Shape();!
Remarques virtual void setWidth(int);!
...!
• une redéfinition de méthode virtuelle
};!
est automatiquement virtuelle
Rect
• la fonction doit avoir la même signature
class Rect : public Shape {!
sinon c'est de la surcharge !
~Rect();!
void setWidth(int) override;!
...!
• sauf que le type de retour peut être une sous-classe
};!
(covariance des types de retour)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 68
Méthodes non virtuelles Shape
class Shape {!
virtual ~Shape();!
Utiles dans quel cas ? virtual void setWidth(int);!
...!
• si classe pas héritée };!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 69
Méthodes et classes abstraites
class Shape { !
public:!
virtual void setWidth(unsigned int) = 0; // méthode abstraite !
...!
};!
Méthode abstraite
– spécification d'un concept dont la réalisation diffère selon les sous-classes
• pas implémentée
• doit être redéfinie et implémentée dans les sous-classes instanciables
Classe abstraite
– classe dont au moins une méthode est abstraite
Java
– pareil mais mot clé abstract
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 70
Bénéfices des classes abstraites
class Shape { !
public:!
virtual void setWidth(unsigned int) = 0; // méthode abstraite !
...!
};!
Méthode abstraite
– spécification d'un concept dont la réalisation diffère selon les sous-classes
• pas implémentée
• doit être redéfinie et implémentée dans les sous-classes instantiables
Traiter un ensemble de classes liées entre
Imposer une spécification que les
elles : sous-classes doivent implémenter
• de manière uniforme sans considérer
• sinon erreur de compilation !
leurs détails • façon de « mettre l'UML dans le code »
• avec un degré d'abstraction plus élevé
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 71
Exemple de classe abstraite
class Shape { !
int x, y;! implémentation commune !
public:! à toutes les sous-classes!
Shape() : x(0), y(0) {}!
Shape(int x, int y) : x(x), y(y) {}!
!
int getX() const {return x;}!
int getY() const {return y;}!
virtual unsigned int getWidth() const = 0;! méthodes abstraites:!
virtual unsigned int getHeight() const = 0;! l’implémentation dépend des
virtual unsigned int getArea() const = 0; ! sous-classes!
.... !
};!
!
doivent être implémentées!
class Circle : public Shape {!
dans les sous-classes !
unsigned int radius;!
public:!
Circle() : radius(0) {}!
Circle(int x, int y, unsigned int r) : Shape(x, y), radius(r) {}!
!
unsigned int getRadius() const {return radius;}!
virtual unsigned int getWidth() const {return 2 * radius;}!
virtual unsigned int getHeight() const {return 2 * radius;}!
virtual unsigned int getArea() const {return PI * radius * radius;}!
.... !
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 72
Interfaces
class Shape { !
public:! pas de variables d'instance
ni de constructeurs!
virtual int getX() const = 0;!
virtual int getY() const = 0;!
virtual unsigned int getWidth() const = 0;!
toutes les méthodes sont
virtual unsigned int getHeight() const = 0;!
abstraites!
virtual unsigned int getArea() const = 0; !
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 73
Traitements uniformes
#include "Rect.h"!
#include "Circle.h"!
!
void foo() {!
Shape ** shapes = new Shape * [10];! tableau de 10 Shape *!
printShapes(shapes, count);!
}!
#include <iostream>!
#include "Shape.h"!
!
void printShapes(Shape ** tab, unsigned int count) {!
for (unsigned int k = 0; k < count; ++k) {!
cout << "Area = " << tab[k]->getArea() << endl;!
}!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 74
Tableaux dynamiques
int * tab = new int[10];! tableau de 10 int!
...!
delete [] tab; // ne pas oublier []!
!
pointeur tab!
pointeur shapes!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 75
Traitements uniformes (2)
#include "Rect.h"!
#include "Circle.h"!
! équivaut à:!
void foo() {! shapes[count] = ...;!
Shape ** shapes = new Shape * [10];! count++;!
printShapes(shapes, count);!
}!
shapes!
chaque élément !
est un Shape *!
instance instance instance
de Circle de Rect de Square
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 76
Magie du polymorphisme
taille en paramètre!
#include <iostream>!
pas d'autre moyen !
#include "Shape.h"! de la connaître !!
!
void printShapes(Shape ** tab, unsigned int count) {!
for (unsigned int k = 0; k < count; ++k) {!
cout << "Area = " << tab[k]->getArea() << endl;!
}!
}!
shapes!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 77
Magie du polymorphisme
#include <iostream>!
#include "Shape.h"!
!
void printShapes(Shape ** tab, unsigned int count) {!
for (unsigned int k = 0; k < count; ++k) {!
cout << "Area = " << tab[k]->getArea() << endl;!
}!
}!
Remarque
– cette fonction ignore l'existence de Circle, Rect, Square !
Mission accomplie !
– on peut traiter un ensemble de classes liées entre elles de manière uniforme
sans considérer leurs détails
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 78
Chaînage des méthodes
Règle générale : éviter les duplications de code
– à plus ou moins long terme ca diverge !
⇒ code difficile à comprendre
⇒ difficile à maintenir
⇒ probablement buggé !
Solutions
– utiliser l’héritage !
– le cas échéant, chaîner les méthodes des superclasses !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 79
Concepts fondamentaux de l’orienté objet
En résumé : 4 fondamentaux
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 80
Implémentation des méthodes virtuelles
class Vehicle {!
public:!
class Vehicle { !
virtual void start();!
....!
virtual int getColor(); !
};!
...!
!
};!
!
class Car : public Vehicle {!
public:! Car Truck
void start() override;! class Car { ! class Truck {!
virtual void setDoors(int doors);! ....! ....!
};!
...! };!
!
};! !
!
class Truck : public Vehicle {!
public:!
void start() override;!
virtual void setPayload(int payload);!
...!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 81
Implémentation des méthodes virtuelles
class Vehicle {!
__VehicleTable * __vtable;!
public:!
virtual void start();!
virtual int getColor(); !
...!
};!
!
class Car : public Vehicle {!
__CarTable * __vtable;!
public:!
void start() override;!
virtual void setDoors(int doors);! vtable
...!
};! • chaque objet pointe vers la vtable de sa classe
! • vtable = tableau de pointeurs de fonctions
class Truck : public Vehicle {!
__TruckTable * __vtable;!
Vehicle * p = new Car();!
public:!
!
void start() override;!
p->start(); == (p->__vtable[0])();!
virtual void setPayload(int payload);!
p->getColor(); == (p->__vtable[1])();!
...!
};!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 82
Coût des méthodes virtuelles
class Vehicle {!
__VehicleTable * __vtable;! Coût mémoire
public:!
un pointeur (__vtable) par objet
virtual void start();!
virtual int getColor(); ! ⇒ méthodes virtuelles inutiles si :
...!
};!
• aucune sous-classe
! • ou aucune redéfinition de méthode
class Car : public Vehicle {!
__CarTable * __vtable;!
public:!
void start() override;! Coût d'exécution
virtual void setDoors(int doors);!
double indirection
...!
};! • coût négligeable sauf si 1 milliard d'appels !
!
class Truck : public Vehicle {!
__TruckTable * __vtable;!
public:!
void start() override;!
virtual void setPayload(int payload);!
...!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 83
Implémentation des méthodes virtuelles
class Vehicle {!
__VehicleTable * __vtable;!
0000000100000ff0 t __ZN3Car5startEv
public:!
0000000100000f40 t __ZN3CarC1Ei
virtual void start();! 0000000100000f70 t __ZN3CarC2Ei
virtual int getColor(); !
...! 00000001000010b0 t __ZN7Vehicle5startEv
};! 0000000100001c70 t __ZN7Vehicle8getColorEv
! 0000000100000fc0 t __ZN7VehicleC2Ei
class Car : public Vehicle {!
__CarTable * __vtable;! 0000000100002150 D __ZTI3Car
public:! 0000000100002140 D __ZTI7Vehicle
void start() override;!
U __ZTVN10__cxxabiv117__class_type_infoE
virtual void setDoors(int doors);!
U __ZTVN10__cxxabiv120__si_class_type_infoE
...!
};!
0000000100000ec0 T _main!
!
class Truck : public Vehicle {!
__TruckTable * __vtable;!
public:!
void start() override;!
virtual void setPayload(int payload);!
...!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 84
Chapitre 3 : Mémoire
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 85
Allocation mémoire
Mémoire automatique (pile/stack) void foo(bool option) { !
int i = 0;!
– variables locales et paramètres
i += 10; !
!
– créées à l'appel de la fonction
string s = "Hello";!
détruites à la sortie de la fonction s += " World";!
s.erase(4, 1);!
– la variable contient la donnée ... !
}!
int
i!
. accède aux champs de l'objet
s! string
– possible pour types de base et objets contrairement à Java (que types de base)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 86
Allocation mémoire
Mémoire globale/statique int glob = 0; // variable globale!
static int stat = 0;!
– variables globales ou static
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 87
Allocation mémoire
Mémoire dynamique (tas/heap) void foo() { !
*s est le pointé
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 88
Allocation mémoire
Mémoire dynamique (tas/heap) void foo() { !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 89
Objets et types de base
C++ int glob = 0;!
C++
static int stat = 0;!
– traite les objets comme les types de base !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 90
Objets et types de base
C++ int glob = 0;! équivalent
– traite les objets comme les types de base
static int stat = 0;! Java
!
void foo() { !
// en Java on écrirait: !
String s = new String("Hello");!
String s = "Hello";!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 91
Sous-objets class Door {!
public:!
Door(Car *);!
....!
};!
class Car : public Vehicle {!
int power;!
Door rightDoor;!
Door * leftDoor;! rightDoor!
Door
public:! contient l'objet (pas possible en Java)
Car() : !
rightDoor(this),!
leftDoor(new Door(this)) { !
leftDoor! Door
}!
};! pointe l'objet (comme Java)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 92
Objets dans des objets
class Car : public Vehicle {!
int power;!
Door rightDoor;!
Door * leftDoor;!
public:!
Car() : !
rightDoor(this),!
leftDoor(new Door(this)) { !
}!
virtual ~Car() {delete leftDoor;} ! leftDoor! Door
...!
};!
Il faut un destructeur !
§ pour détruire les pointés créés par new dans le constructeur (leftDoor)
§ par contre, les objets contenus dans les variables sont autodétruits (rightDoor)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 93
Copie d'objets class Car : public Vehicle {!
int power;!
Door rightDoor;!
Door * leftDoor;!
void foo() {! ...!
Car c("Smart-Fortwo","blue");! };!
Car * p = new Car(Ferrari-599-GTO","red");!
Car myCar;!
! affectation (après la création)
myCar = c;!
myCar = *p; !
myCar! c!
= copie le contenu des objets
power! power!
champ à champ (comme en C)
rightDoor! rightDoor!
* leftDoor! * leftDoor!
Noter l'* : myCar = *p; ...! ...!
Problème ?
Door Door
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 94
Copie d'objets class Car : public Vehicle {!
int power;!
Door rightDoor;!
Door * leftDoor;!
void foo() {! ...!
Car c("Smart-Fortwo","blue");! };!
Car * p = new Car(Ferrari-599-GTO","red");!
Car myCar;!
!
mmyCar et p ont la même porte
myCar = *p; !
gauche !!
Car mySecondCar(c); !
pareil pour mySecondCar et c !
}!
Problème myCar! c!
§ les pointeurs pointent sur
power! power!
le même objet !
rightDoor! rightDoor!
§ pas de sens dans ce cas ! * leftDoor! * leftDoor!
...! ...!
De plus
§ Door est détruit 2 fois !
=> rique de plantage ! Door Door
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 95
Copie superficielle et copie profonde
myCar! c!
Door Door
myCar! c!
Copie profonde (deep) power! power!
§ copie le contenu des pointés
rightDoor! rightDoor!
Et en Java ?
Door Door
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 96
Copie superficielle et copie profonde
Java
§ même problème si l'objet contient des références Java
§ mais = ne permet pas la copie d'objets (mais des méthodes peuvent le faire)
C/C++! Java!
a = new(b);!
Car a(...);! !
n'existe pas en Java
Car b(...);! !
a = b;! copie l'objet (si ! ces fonctions existent)!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 97
Opérateurs de copie
Copy constructor et operateur d'affectation
§ on peut les redéfinir pour faire de la copie profonde, ou les interdire
Copy constructor
class Car : public Vehicle {!
appelé à l’initialisation
....!
Car(const Car& from); ! Car c("Smart","blue");!
Car myThirdCar(c);!
Car& operator=(const Car& from);! !
};!
operator=
appelé à l'affectation
Car mycar;!
myCar = c;!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 98
Opérateurs de copie
Copy constructor et operateur d'affectation
§ = delete interdit de les utiliser
Remarque
§ les copy constructors existent en Java !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 99
Opérateurs de copie class Car : public Vehicle {!
Door rightDoor;!
Door * leftDoor;!
public:!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 100
Tableaux
void foo() {!
int count = 10, i = 5; !
!
delete [] p1;!
ne pas oublier []
delete [] p2;!
delete [] p3;!
}!
tab!
p!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 101
Coût de l'allocation mémoire
Gratuit ou négligeable
Mémoire globale/statique void foo() { !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 102
Coût de l'allocation mémoire
Coûteux
void foo() { !
Mémoire dynamique (tas) : Car * s = new Car();!
• new en C++ (malloc en C) ...!
}!
• ramasse-miettes en Java
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 103
Compléments
Mémoire constante!
§ parfois appelée statique
§ ex : littéraux comme "Hello Word"!
Variables volatile
§ empêchent optimisations du compilateur
§ pour threads ou entrées/sorties selon le langage
En C/C++
Variables globales
§ accessibles dans toutes les fonctions de tous les fichiers => dangereuses !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 104
Chapitre 4 : Types, constance
& smart pointers
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 105
Types de base
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 106
Types normalisés
int8_t !
Portabilité : même taille sur toutes les plateformes
int16_t !
int32_t! Définis dans <cstdint>
int64_t!
intmax_t!
uint8_t!
uint16_t!
uint32_t!
uint64_t!
uintmax_t!
etc.!
!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 107
Noms de types
using (typedef en C) : crée un nouveau nom de type
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 108
Inférence de types
auto : type inféré par le compilateur (C++11)
!
auto count = 10;! int count = 10;!
==
auto PI = 3.1416; ! double PI = 3.1416; !
! !
Rappel: using ShapeList = std::list<Shape *>;!
ShapeList shapes;!
!
auto it = shapes.begin(); ! std::list<Shape *>::iterator it = shapes.begin();
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 109
Constantes
Macros du C (obsolète)
– substitution textuelle avant la compilation #define PORT 3000!
#define HOST "localhost"!
Enumérations
– valeurs intégrales
enum {PORT = 3000};!
– commencent à 0 par défaut
enum Status {OK, BAD, UNKNOWN};!
– existent en Java
enum class Status {OK, BAD, UNKNOWN};!
!
Variables const
– final en Java const int PORT = 3000;!
constexpr (C++11)
– expression calculée à la compilation constexpr const char * HOST = "localhost";!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 110
Objets constants ou immuables
Questions à se poser
§ à qui appartient l'objet (qui le crée, qui le détruit ?)
§ qui a le droit de le lire ?
§ qui a le droit de le modifier ?
Exemple 1
§ tableaux du TP !
Exemple 2
§ Alice a un calendrier partagé
§ ses collègues peuvent le lire mais pas le modifier
⇒ Alice et ses collègues n'ont pas le même point de vue sur l'objet !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 111
Objets constants ou immuables
class User {!
Cal* cal = new Cal;!
!
public:!
User(...) {...}!
void pote(User* alice) {! Cal* getCal() {return cal;}!
Cal* c = alice->getCal();! };!
... !
};!
Problème ?
Cal : classe du calendrier!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 112
Objets constants ou immuables
class User {!
Cal* cal = new Cal;!
!
public:!
User(...) {...}!
void pote(User* alice) {! Cal* getCal() {return cal;}!
Cal* c = alice->getCal();! };!
... !
};!
Problème !
§ pote() peut modifier le contenu du calendrier d'Alice !
Solutions ?
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 113
Objets immuables
class User {!
Cal* cal = new Cal;!
!
public:!
User(...) {...}!
void pote(User* alice) {! Cal* getCal() {return cal;}!
Cal* c = alice->getCal();! };!
... !
};!
§ pas applicable ici : Alice ne pourrait pas modifier son propre calendrier !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 114
Objets constants
class User {!
Cal* cal = new Cal;!
!
public:!
User(...) {...}!
void pote(const User* alice) {! const Cal* getCal() const {return cal;}!
const Cal* c = alice->getCal();! };!
... !
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 115
Copie
class User {!
Cal* cal = new Cal;!
!
public:!
User(...) {...}!
void pote(const User* alice) {! const Cal* getCal() const {return cal;}!
Cal* c = new Cal(*alice->getCal());! };!
... !
};!
Solution 3 : copie
§ c pointe sur une copie du calendrier
§ les contenus ne sont plus synchronisés
§ parfois c'est ce qu'on veut (cf. TP) :
• ex : garder l'historique
• ex : l'objet d'origine peut être détruit sans qu'on soit averti
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 116
const sert aussi à éviter les bugs !
class Plane {!
double pitch;!
....!
public:!
double getPitch() const {!
return pitch = 0.12;!
}!
!
void setPitch(double angle);!
ooops typo !!
...!
erreur de compil car méthode const!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 117
Pointeurs et pointés
Qu’est-ce qui est constant : le pointeur ou le pointé ?
// *s est constant:
const char * s!
pointeur! pointé
char const * s!
!
!
// s est constant:! pointeur! pointé
char * const s!
!
!
// les deux sont constants:!
pointeur! pointé
const char * const s !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 118
Constance logique
class Doc {!
string text;!
mutable Printer * printer; // peut être modifiée même si Doc est const!
public:!
Doc() : printer(nullptr) {}!
void print() const {!
if (!printer) printer = new Printer(); // OK car printer est mutable!
}!
....!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 119
Smart pointers
#include <memory>!
!
void foo() {!
shared_ptr<Circle> p(new Circle(0, 0, 50)); // count=1!
shared_ptr<Circle> p2;!
shared_ptr (C++11)
§ smart pointer avec comptage de références
• objet auto-détruit quand le compteur arrive à 0
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 120
Smart pointers class Shape {!
Shape
void foo() {!
shared_ptr<Shape> p(new Circle(0, 0, 50)); ! Circle
class Circle: public Shape {!
p->setWith(20);!
virtual void setWidth(int);!
}!
...!
}!
Attention !
§ doivent pointer sur des objets crées avec new
§ pas convertibles en raw pointers (perd le compteur)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 121
Smart pointers
#include <memory>!
!
void foo() {!
vector< unique_ptr<Shape> > vect;!
weak_ptr
§ pointe un objet sans le "posséder"
§ permet de tester si l'objet existe encore
§ utiles si dépendances circulaires
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 122
Chapitre 5 : Bases des Templates et STL
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 123
Programmation générique
template <typename T> !
T mymax(T x, T y) {return (x > y ? x : y);}!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 124
Classes templates
template <typename T> class Matrix {!
public:!
void set(int i, int j, T val) { ... }!
T peut être ce qu'on veut
T get(int i, int j) const { ... }! § pourvu que ce soit compatible
void print() const { ... }! avec les méthodes de Matrix
....!
};!
!
template <typename T> !
Matrix<T> operator+(Matrix<T> m1, Matrix<T> m2) { !
.... !
}!
!
Matrix<float> a, b;!
a.set(0, 0, 10);!
a.set(0, 1, 20);!
....!
Matrix<float> res = a + b;! appelle: operator+(a,b)!
res.print();!
!
Matrix<complex> cmat;!
Matrix<string> smat; // why not?!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 125
Exemple
passage par const référence!
template <typename T, int L, int C> ! (chapitre suivant)!
class Matrix {!
T values[L * C];!
public:!
void set(int i, int j, const T & val) {values[i * C + j] = val;}!
const T& get(int i, int j) const {return values[i * C + j];}!
void print() const {!
for (int i = 0; i < L; ++i) {!
for (int j = 0; j < C; ++j) cout << get(i,j) << " ";!
cout << endl;!
}!
}!
};!
!
template <typename T, int L, int C> !
Matrix<T,L,C> operator+(const Matrix<T,L,C> & a, const Matrix<T,L,C> & b) {!
Matrix<T,L,C> res;!
for (int i = 0; i < L; ++i)!
for (int j = 0; j < C; ++j) !
res.set(i, j, a.get(i,j) + b.get(i,j));!
return res;! NB: on verra une solution plus
}! performante au chapitre suivant!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 126
Standard Template Library (STL)
std::vector<int> v(3); // vecteur de 3 entiers!
v[0] = 7;!
v[1] = v[0] + 3;!
v[2] = v[0] + v[1];!
reverse(v.begin(), v.end());!
Conteneurs
– pour traiter une collection d'objets
– compatibles avec objets et types de base (contrairement à Java)
– gèrent automatiquement leur mémoire
• exples : array, vector, list, map, set, deque, queue, stack ...
Itérateurs
– pour pointer sur les éléments des conteneurs : ex : begin() et end()
Algorithmes
– manipulent les données des conteneurs : ex : reverse()
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 127
Vecteurs
!
class Point {!
int x, y;!
public:!
Point(int x, int y) : x(x), y(y) {}!
#include <vector>!
! void print() const;!
};!
void foo() {!
std::vector<Point> path; !
path.push_back(Point(20,20));!
path.push_back(Point(50,50));! path contient les Points :!
path.push_back(Point(70,70));!
x! x! x!
for (unsigned int i=0; i < path.size(); ++i) {! y! y! y!
path[i].print();!
}! chaque élément !
}! est un objet Point!
En théorie
§ vecteurs peu efficaces pour l'insertion/suppression d'éléments
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 128
Listes et itérateurs
#include <list>!
begin()! end()!
!
void foo() {!
std::list<Point> path; ! path!
path.push_back(Point(20,20)); ! x! x! x!
path.push_back(Point(50,50));! y! y! y!
path.push_back(Point(70,70));!
!
for (auto & it : path) it.print();!
}!
En théorie
§ listes efficaces pour l'insertion/suppression d'éléments
En réalité
§ les vecteurs sont presque toujours plus rapides
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 129
Listes et itérateurs
#include <list>!
begin()! end()!
!
void foo() {!
std::list<Point> path; ! path!
path.push_back(Point(20,20)); ! x! x! x!
path.push_back(Point(50,50));! y! y! y!
path.push_back(Point(70,70));!
!
for (auto & it : path) it.print();!
}!
Equivaut à :
!
for (std::list<Point>::iterator it = path.begin(); it != path.end(); ++it) {!
(*it).print();!
}!
parenthèses nécessaires!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 130
Conteneurs et pointeurs
#include <list>! #include <list>!
! !
for (auto & it : path) it.print();! for (auto & it : path) it->print();!
}! }!
path! path!
x! x! x!
y! y! y!
x! x! x!
y! y! y!
§ A gauche : la liste contient les éléments
§ A droite: la liste pointe sur les éléments
Problème ?
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 131
Conteneurs et pointeurs
#include <list>! #include <list>!
! !
for (auto & it : path) it.print();! for (auto & it : path) it->print();!
}! }!
path! path!
x! x! x!
y! y! y!
Détruit!
x! x! x!
y! y! y!
Problème à droite !
§ la liste est détruite (path est dans la pile)
§ mais pas les pointés ! Pas détruit!
Solutions ?
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 132
Conteneurs et pointeurs
#include <list>!
!
void foo() {!
std::list<Point> path; !
path.push_back(Point(20,20)); !
path.push_back(Point(50,50));!
path.push_back(Point(70,70));!
!
for (auto & it : path) it.print();!
}!
path!
x! x! x!
y! y! y!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 133
Conteneurs et pointeurs Vehicle
class Vehicle { !
....!
path.push_back(Point(20,20)); !
path.push_back(Point(50,50));!
Car Truck
path.push_back(Point(70,70));! class Car { ! class Truck {!
! ....! ....!
for (auto & it : path) it.print();! };! };!
}! !
!
path!
x! x! x!
y! y! y!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 134
Conteneurs et pointeurs Vehicle
class Vehicle { !
....!
Solution 2 : pointeurs };!
!
#include <list>!
!
void foo() {!
std::list<Vehicule *> v; ! Car Truck
v.push_back(new Car()); !
class Car { ! class Truck {!
v.push_back(new Truck());! ....! ....!
v.push_back(new Train());! };! };!
!
!
for (auto & it : v) it->print();! !
...!
for (auto & it : v) delete it;!
}!
void foo() {!
std::list<shared_ptr<Vehicule>> v;!
v.push_back(make_shared<Car>()); !
....!
}! ou: v.push_back(shared_ptr<Car>(new Car))
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 135
Enlever des éléments
Enlever tous les éléments
std::vector<int> v{0, 1, 2, 3, 4, 5};!
v.clear(); // enlève tout!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 136
Enlever des éléments
Enlever les éléments ayant une certaine valeur
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 137
Deque ("deck")
#include <deque>!
!
void foo() {!
std::deque<Point> path; !
path.push_back(Point(20, 20)); !
path.push_back(Point(50, 50));!
path.push_back(Point(70, 70));!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 138
Enlever plusieurs éléments dans une liste
std::list<Point> path;!
int value = 200; // détruire les points dont x vaut 200!
!
for (auto it = path.begin(); it != path.end(); ) {!
if ((*it)->x != value) it++;!
else {!
auto it2 = it; !
++it2;!
delete *it; // détruit l'objet pointé par l'itérateur!
path.erase(it); // it est invalide après erase()!
it = it2;!
}!
}!
path!
Attention
§ l'itérateur it est invalide après erase()
=> second itérateur it2 x! x! x! x!
y! y! y! y!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 139
Table associative (map) class User {!
string name,!
int id;!
public:!
#include <iostream>! User(const string& name, int id);!
#include <map>! int getID() const {return id;}!
! ....!
};!
using Dict = std::map<string, User*>; !
!
void foo() {!
Dict dict; !
dict["Dupont"] = new User("Dupont", 666); // ajout!
dict["Einstein"] = new User("Einstein", 314);!
!
auto it = dict.find("Dupont"); // recherche!
if (it == dict.end()) !
std::cout << "pas trouvé" << std::endl;!
else !
std::cout << "id: " << it->second->getID() << std::endl;!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 140
Algorithmes exemple : trier les éléments d’un conteneur
#include <string>!
#include <vector>!
#include <algorithm>!
!
class User {!
string name;!
public:!
User(const string & name) : name(name) {}!
friend bool compareEntries(const User &, const User &);!
};!
!
// inline nécessaire si la fonction est définie dans un header!
inline bool compareEntries(const User & e1, const User & e2) { !
return e1.name < e2.name;!
}!
!
void foo() {!
std::vector<User> entries;!
....!
std::sort(entries.begin(), entries.end(), compareEntries);!
....!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 141
Template metaprogramming
calcule factorielle !
template <int N> struct Factorial {! à la compilation !!
static const int value = N * Factorial<N-1>::value;!
};!
!
spécialisation !
template <> struct Factorial<0> {!
de template!
static const int value = 1;!
};!
!
void foo() {!
int x = Factorial<4>::value; // vaut 24! instanciation!
int y = Factorial<0>::value; // vaut 1! récursive!
}!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 142
Polymorphisme paramétré
Comment avoir une fonction print() générique ?
void foo() {!
!
print(55);! class Point {!
! int x, y;!
std::string s = "toto";! public:!
Point(int x, int y) : x(x), y(y) {}!
print(s);!
void print() const;!
! };!
Point p(10,20);!
print(p);!
!
std::vector<int> vi{0, 1, 2, 3, 4, 5};!
print(vi);!
!
std::vector<Point> vp{{0, 1},{2, 3},{4, 5}};!
print(vp);!
!
std::list<Point> lp{{0, 1},{2, 3},{4, 5}};!
print(lp);!
}!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 143
Polymorphisme paramétré
template <typename T> void print(const T & arg) {!
cas général! cout << arg << endl;!
! }!
!
spécialisation! template <> void print(const Point & p) {!
totale! p.print(cout); !
}!
!
spécialisations! template <typename T> void print(const std::vector<T> & v) {!
partielles! for (auto& it : v) print(it);!
}!
!
template <typename T> void print(const std::list<T> & l) {!
void foo() {! for (auto& it : l) print(it);!
print(55);! }!
!
string s = "toto";! !
print(s);!
Point p(10,20);! C'est une autre forme de polymorphisme
print(p);!
effectuée à la compilation
std::vector<int> vi{0, 1, 2, 3, 4, 5};!
print(vi);!
std::vector<Point> vp{{0, 1},{2, 3},{4, 5}};! Amélioration:
print(vp);! même définitition pour tous les conteneurs :
std::list<Point> lp{{0, 1},{2, 3},{4, 5}};!
=> comment les détecter ?
print(lp);!
}!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 144
Traits <type_traits>
is_array<T>!
is_object<T>!
is_class<T>!
is_abstract<T>!
is_enum<T>! is_polymorphic<T>! #include <type_traits>!
is_floating_point<T>! is_base_of<Base,Derived>!
is_function<T>! is_same<T,V>!
is_integral<T>! etc.!
is_pointer<T>!
is_arithmetic<T>!
!
void foo() {!
cout << is_integral<int>::value << endl; // 1!
cout << is_integral<float>::value << endl; // 0!
Il n'y a pas is_container<>
cout << is_class<int>::value << endl; // 0! Comment le définir ?
cout << is_class<Point>::value << endl; // 1!
}!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 145
Type matching
template <typename T> struct is_container {! cas général!
static const bool value = false;!
};!
!
template <typename T> struct is_container<std::vector<T>> {!
static const bool value = true;! spécialisations!
};! partielles!
!
template <typename T> struct is_container<std::list<T>> {!
static const bool value = true;!
};!
!
// ... etc.!
!
void foo() {!
cout << is_container<int>::value << endl; // 0 (false)!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 146
Conditions sur les types
!
template <typename T> !
void print(const T& arg,!
typename std::enable_if< !is_container<T>::value, bool>::type = true) {!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 147
Templates C++ vs. Generics Java
template <typename T> !
T max(T x, T y) {return (x > y ? x : y);}!
!
i = max(4, 10);!
x = max(6666., 77777.);!
!
Templates C++
§ instanciation à la compilation => optimisation prenant compte des types
Generics Java
Sémantique et implémentation différentes :
§ pas pour types de base
§ pas instanciés à la compilation, pas de spécialisation
§ pas de calcul sur les types (les types sont « effacés »)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 148
Chapitre 6 :
Passage par valeur et par référence
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 149
Passer des valeurs à une fonction
class Truc {! C++ class Truc {! Java
void print(int n, const string * p) {! void print(int n, String p) {!
cout << n << " " << *p << endl;! System.out.println(n + " " + p);!
}! }!
! !
void foo() {! void foo() {!
int i = 10;! int i = 10;!
string * s = new string("YES");! String s = new String("YES");!
print(i, s); print(i,
! s);
}! }!
...! ...!
};! }!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 150
Passer des valeurs à une fonction
class Truc {! C++ class Truc {! Java
void print(int n, const string * p) {! void print(int n, String p) {!
cout << n << " " << *p << endl;! System.out.println(n + " " + p);!
}! }!
! !
void foo() {! void foo() {!
int i = 10;! int i = 10;!
string * s = new string("YES");! String s = new String("YES");!
print(i, s); print(i,
! s);
}! }!
...! ...!
};! }!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 151
Passer des valeurs à une fonction
class Truc {! C++ class Truc {! Java
void print(int n, const string * p) {! void print(int n, String p) {!
cout << n << " " << *p << endl;! System.out.println(n + " " + p);!
}! }!
! !
...! ...!
};! }!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 152
Passer des valeurs à une fonction
class Truc {! C++ class Truc {! Java
void print(int n, const string * p) {! void print(int n, String p) {!
cout << n << " " << *p << endl;! System.out.println(n + " " + p);!
}! }!
! !
...! ...!
};! }!
• en C/C++ : const * !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 153
Récupérer des valeurs d'une fonction
class Truc {! C++ class Truc {! Java
void get(int n, const string * p) {! void get(int n, String p) {!
n = 20;! n = 20;!
p = new string("NO");! p = new String("NO");!
}! }!
! !
void foo() {! void foo() {!
int i = 10;! int i = 10;!
string * s = new string("YES");! String s = new String("YES");!
get(i, s); ! get(i, s);!
cout << i << " " << *s << endl; !
System.out.println(i + " " + s);
}! }!
! !
...! ...!
};! }!
Résultat
§ 10 YES
§ 20 NO
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 154
Récupérer des valeurs d'une fonction
class Truc {! C++ class Truc {! Java
void get(int n, const string * p) {! void get(int n, String p) {!
n = 20;! n = 20;!
p = new string("NO");! p = new String("NO");!
}! }!
! !
void foo() {! void foo() {!
int i = 10;! int i = 10;!
string * s = new string("YES");! String s = new String("YES");!
get(i, s); ! get(i, s);!
cout << i << " " << *s << endl; !
System.out.println(i + " " + s);
}! }!
...! ...!
};! }!
Résultat : 10 YES
§ passage par valeur => arguments inchangés
p! NO
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 155
Récupérer des valeurs d'une fonction
class Truc {! C++
void get(int & n, string & p) {! & : passage par référence !
n = 20;!
p = "NO";!
}!
!
void foo() {!
int i = 10;!
string s("YES");!
get(i, s); !
cout << i << " " << *s << endl; !
affiche: 20 NO!
}!
...!
};!
Et en Java ?
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 156
Récupérer des valeurs d'une fonction
Le passage par référence (ou similaire) existe aussi dans C#, Pascal, Ada, etc.
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 157
Récupérer des valeurs d'une fonction
class Truc {! C++ class Truc {! Java
void get(int * n, string * p) {! void get(StringBuffer p) {!
*n = 20;! p.replace(0, p.lenghth(), "NO");!
*p = "NO"; ! }!
}! !
! void foo() {!
modifier les pointés
void foo() {! StringBuffer s = new StringBufer("YES");!
int i = 10;! get(s);!
string * s = new string("YES");! System.out.println(i + " " + s);
get(&i, s); ! }!
cout << i << " " << *s << endl; ...! !
}! }!
...!
};!
En Java :
s! NO
§ seulement avec objets mutables
§ pas possible avec types de base !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 158
Passage des objets en C++
class Truc {! C++
void print(int n, string p) {! pas de & ni de * !
cout << n << " " << p << endl;!
}!
!
void foo() {!
int i = 10;!
string s("YES");!
print(i, s); !
}!
...!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 159
Passage par const référence
class Truc {! C++
void print(int n, const string & p) {!
cout << n << " " << p << endl;!
}!
!
void foo() {!
int i = 10;!
string s("YES");!
print(i, s); !
}!
...!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 160
Retour par const référence
class Truc {! C++
string name_;!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 161
Références C++
Ce sont des alias :
- doivent être initialisées : référencent toujours la même entité
- pas de calcul d'adresses dangereux (contrairement aux pointeurs)
Circle c;!
Circle & ref = c; // ref sera toujours un alias de c!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 162
Chapitre 7 : Compléments
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 163
Transtypage vers les superclasses
class Object {! Object
...! class Object {!
};! ...!
!
!
class Button : public Object {! }!
...!
};!
!
void foo() {! Button
Object * obj = new Object();! class Button: public Object {!
Button * but = new Button();! ...!
!
obj = but; // correct?!
}!
but = obj; // correct?!
}!
Rappel : Correct ?
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 164
Transtypage vers les superclasses
class Object {!
...!
Tous les cèpes sont des bolets,
};!
!
mais tous les bolets ne sont pas
class Button : public Object {! des cèpes.!
...!
};!
!
void foo() {!
Object * obj = new Object();!
Button * but = new Button();!
obj = but; ! OK: upcasting
Rappel : héritage
§ transtypage implicite vers les super-classes (upcasting)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 165
Transtypage vers les sous-classes
Object
class Object {!
class Object {!
// pas de méthode draw()! ...!
...! }!
};!
!
class Button : public Object {!
virtual void draw();!
...!
};!
Button
! class Button: public Object {!
void foo(Object * obj) {! virtual void draw();!
obj->draw(); // correct ? ! ...!
}! }!
!
void bar() {!
foo(new Button()); !
}!
!
Correct ?
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 166
Transtypage vers les sous-classes
Object
class Object {!
class Object {!
// pas de methode draw()! ...!
...! }!
};!
!
class Button : public Object {!
virtual void draw();!
...!
};!
Button
! class Button: public Object {!
void foo(Object * obj) {! virtual void draw();!
obj->draw(); ! ...!
}! }!
!
void bar() {!
foo(new Button()); !
}! erreur de compilation: draw() !
! pas une méthode de Object!
Que faire ?
§ si on ne peut pas modifier Object ni la signature de foo()
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 167
Transtypage vers les sous-classes
class Object {!
...!
};!
!
void bar() {!
foo(new Button()); !
}!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 168
Transtypage dynamique
class Object {!
...!
};!
!
void bar() {!
foo(new Button()); !
}!
!
Bonne solution
§ contrôle dynamique du type à l'exécution
§ Java : tester avec isinstanceof, puis faire un cast (ou cast + vérifier exceptions)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 169
Opérateurs de transtypage
dynamic_cast<Type>(b)
• vérification du type à l'exécution : opérateur sûr
static_cast<Type>(b)
• conversions de types "raisonnables" : à utiliser avec prudence
reinterpret_cast<Type>(b)
• conversions de types "radicales" : à utiliser avec encore plus de prudence !
const_cast<Type>(b)
• pour enlever our rajouter const
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 170
RTTI (typeid)
#include <typeinfo>!
!
void printClassName(Shape * p) {!
cout << typeid(*p).name() << endl;!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 171
Types incomplets et handle classes
#include <Widget>! header Button.h!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 172
Types incomplets
#include <Widget>! header Button.h!
Problème
§ erreur de compilation: ButtonImpl et MouseEvent sont inconnus !
Solution ?
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 173
Types incomplets
#include <Widget>! header Button.h!
#include <Event.h>!
#include "ButtonImpl.h"!
Mauvaise solution
§ l'implémentation n'est plus cachée : il faut donner ButtonImpl.h au client !
§ plein de headers qui s'incluent les uns les autres !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 174
Types incomplets
#include <Widget>! header Button.h!
class Event;!
class ButtonImpl;!
§ les variables (event, impl) doivent être des pointeurs ou des références
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 175
Pointeurs de fonctions et lambdas
class Data {!
public:!
std::string firstName, lastName;!
int id, age;! test = fonction!
....! appelée par search()!
};!
!
using DataList = std::list< Data* >;!
!
class DataBase {!
public:!
DataList search( std::function<bool(const Data&)> test ) const;!
....!
};!
!
!
Problème
§ DataBase contient des Data !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 176
Pointeurs class Data {!
public:!
de fonctions
std::string firstName, lastName;!
int id, age;!
....!
};!
!
using DataList = std::list< Data* >;!
!
class DataBase {!
public:!
DataList search(std::function<bool(const Data&)> test) const;!
....!
};!
Exemple !
!
Limitation
§ il faut écrire une fonction pour chaque age ! (et pour tous les autres critères)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 177
Lambdas class Data {!
public:!
std::string firstName, lastName;!
int id, age;!
....!
};!
!
using DataList = std::list< Data* >;!
!
class DataBase {!
public:!
DataList search(std::function<bool(const Data&)> test) const;!
....!
};!
Plus puissant ! !
!
void foo(const DataBase& base) {! lambda qui capture les vars de foo() !
int age = 10;!
DataList res = base.search( [=](const Data& d) {return d.age > age;} );!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 178
Lambdas et capture de variables
void foo(const DataBase& base) {!
lambda qui capture seulement age!
int age = 10;!
DataList res = base.search( [age](const Data& d) {return d.age > age;} );!
}!
Options
§ [] : capture rien
§ [=] : capture par valeur (y compris this dans un objet)
§ [&] : capture par référence (pour modifier les variables)
§ [age] : capture age par valeur (age est copié)
§ type de retour implicite sinon écrire :
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 179
Types de pointeurs de fonctions
Plusieurs solutions
§ pointeurs de fonctions
§ pointeurs de méthodes
§ pointeurs de fonctions généralisés
§ peuvent pointer n'importe quel type de fonction ou une lambda
void doIt(Event&) {!
Exemple cout << "Done!" << endl;!
}!
§ fonctions de callback des
!
boites à outils graphiques void foo() {!
Button * btn = new Button("OK");!
btn->addCallback(doIt);!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 180
Pointeurs de fonctions généralisés
class Button : public Widget {!
public:!
void addCallback(std::function< void(Event&) > fun) {!
fun_ = fun;!
}!
protected:!
std::function< void(Event&) > fun_ = nullptr;!
void callCallback(int x, int y) {!
Event e(x,y);!
if (fun_) (fun_)(e);!
}!
};!
!
void doIt(Event&) {!
cout << "Done!" << endl;!
}! pointeur de fonction généralisé (C++11)!
!
void foo() {!
Button * btn = new Button("OK");!
btn->addCallback(doIt);!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 181
Pointeurs de fonctions non-membres
class Button : public Widget {!
Pour les fonctions : public:!
void addCallback( void (*fun)(Event&) ) {!
• non-membres fun_ = fun;!
}!
• ou static
protected:!
void (*fun_)(Event&) > = nullptr;!
void callCallback(int x, int y) {!
Event e(x,y);!
if (fun_) (fun_)(e);!
}!
};!
!
void doIt(Event&) {!
cout << "Done!" << endl;!
}!
!
void foo() {! pointeur de fonction (comme en C)!
Button * btn = new Button("OK");! (noter l'*)!
btn->addCallback(doIt);!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 182
Pointeurs de méthodes
class Button : public Widget {!
Pour les méthodes d'instances public:!
void addCallback(Truc* obj, !
void(Truc::*fun)(Event&)){!
obj_ = obj;!
fun_ = fun;!
}!
!
class Truc {!
string result;! protected:!
public:! Truc * obj_ = nullptr;!
void doIt(Event& e) {! void(Truc::*fun_)(Event&) = nullptr;!
cout << "Result:" << result << endl;!
}! void callCallback(int x, int y) {!
};!
Event e(x,y);!
!
if (obj_ && fun_) (obj_ -> *fun_)(e);!
void foo() {!
}!
Truc * truc = new Truc();!
};!
Button * btn = new Button("OK");! !
btn->addCallback(truc, &Truc::doIt);!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 183
Foncteurs
class Button : public Widget {!
§ l'objet est considéré comme une fonction public:!
void addCallback(Truc* obj){!
§ plus besoin de passer l'objet en argument ! obj_ = obj;!
}!
§ il suffit de définir operator() !
protected:!
Truc * obj_ = nullptr;!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 184
Surcharge des opérateurs
#include <string>! class string {!
! friend string operator+(const string&, const char*);!
string s = "La tour"; !
string& operator+=(const char*);!
s = s + " Eiffel";!
....!
s += " est bleue";! };!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 185
Exemple : smart pointers intrusifs
class Shape {!
public:!
Shape() : counter(0) {}!
private:!
long counter;!
friend void intrusive_ptr_add_ref(Pointable* p);!
friend void intrusive_ptr_release(Pointable* p);!
friend long intrusive_ptr_get_count(Pointable* p);!
};!
!
Principe
– la classe de base possède un compteur de références
– les smart pointers détectent les affectations et modifient le compteur
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 186
Exemple : smart pointers intrusifs
template <class T> !
class intrusive_ptr {!
T* p;!
public:!
intrusive_ptr(T* obj) : p(obj) {if (p != NULL) intrusive_ptr_add_ref(p);}!
~intrusive_ptr() {if (p) intrusive_ptr_release(p);}!
intrusive_ptr& operator=(T* obj) {....}!
T* operator->() const {return p;} // la magie est la ! !
T& operator*() const {return *p;} !
.....!
};!
!
void foo() {!
intrusive_ptr<Shape> ptr = new Circle(0, 0, 50);!
ptr->setX(20); // fait ptr.p->setX(20)!
} // ptr est détruit car dans la pile => appelle destructeur!
// => appelle intrusive_ptr_release()!
!
Le smart pointer
– encapsule un raw pointer
– surcharge le copy constructor, et les operateurs = , -> et *
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 187
Exceptions
class MathErr {}; !
!
class Overflow : public MathErr {};!
!
struct Zerodivide : public MathErr {!
int x;!
Zerodivide(int x) : x(x) {}!
};!
!
void foo() {!
try {!
int z = calcul(4, 0)!
}!
catch(Zerodivide & e) { cerr << e.x << "divisé par 0" << endl; }!
catch(MathErr) { cerr << "erreur de calcul" << endl; }!
catch(...) { cerr << "autre erreur" << endl; }!
}!
!
int calcul(int x, int y) {!
return divise(x, y);!
}!
!
int divise(int x, int y) {!
if (y == 0) throw Zerodivide(x); // throw leve l'exception!
else return x / y;!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 188
Exceptions
void foo() {!
But : faciliter le traitement des erreurs try {!
int z = calcul(4, 0)!
- remontent dans la pile des appels de fonctions
}!
- jusqu'à un point de contrôle catch(Zerodivide & e) {...}!
catch(MathErr) {...}!
catch(...) {...}!
}!
Avantages
- gestion centralisée et systématique des erreurs
• évitent d'avoir tester et propager des codes d'erreurs
dans une myriade de fonctions
Inconvénient
- peuvent rendre le flux d'exécution difficile à comprendre si on en abuse
• => à utiliser à bon escient et avec modération !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 189
Exceptions
Différences entre C++ et Java
- en C++ on peut renvoyer ce qu'on veut (pas seulement des objets)
- en Java les fonctions doivent spécifier les exceptions
!
int divise(int x, int y) throws Zerodivide, Overflow {...} // Java!
!
int divise(int x, int y); // C++!
!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 190
Exceptions
Exceptions standards
- exception : classe de base ; header : <exception>
- runtime_error
- bad_alloc, bad_cast, bad_typeid, bad_exception, out_of_range ...
Handlers
- set_terminate() et set_unexpected() spécifient ce qui se passe en dernier recours
Redéclenchement
try {!
..etc..!
d'exceptions }!
!
catch (MathErr& e) {!
if (can_handle(e)) {!
..etc..!
return;!
}!
else {!
..etc..!
throw; // relance l'exception!
}!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 191
Assertions
#include <Square.h>!
#include <assert.h>!
!
void changeSize(Square * obj, unsigned int size) {!
assert(obj);! précondition!
obj->setWitdth(size);!
assert(obj->getWith() == obj->getHeight());! postcondition!
}!
Remarques
- il est dangereux de ne faire aucun test en mode production (exceptions faites pour cela)
- préférer les tests unitaires (ex : GoogleTest, CppTest, CppUnit)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 192
Une source d'erreur fréquente...
Attention !
void changeSize(Square * obj, unsigned int size) {!
- le pointeur peut être nul ! obj->setWitdth(size);!
- ca arrive souvent ... }!
!
Mieux ! void changeSize(Square * obj, unsigned int size) {!
- lancer une exception if (obj) obj->setWitdth(size);!
else throw NullPointer("changeSize");!
- c'est ce que fait Java }!
!
Encore mieux ! void changeSize(Square & obj, unsigned int size) {!
- une référence C++ ne peut
obj.setWitdth(size);!
pas être nulle }!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 193
Une source d'erreur fréquente...
#include <string>!
#include <stdexcept>!
!
struct NullPointer : public runtime_error {!
explicit NullPointer(const std::string & what) !
: runtime_error("Error: Null pointer in" + what) {}!
explicit NullPointer(int line, const char * file) !
: runtime_error("Error: Null pointer at line "+to_string(line)+" of file: "+file) {}!
};!
!
#define CheckPtr(obj) (obj ? obj : throw NullPointer(__LINE__,__FILE__),obj)!
!
!
void changeSize(Square * obj, unsigned int size) {!
if (obj) obj->setWitdth(size);!
else throw NullPointer("changeSize");!
}!
!
void changeSize(Square * obj, unsigned int size) {!
CheckPtr(obj)->setWitdth(size);!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 194
Héritage multiple
class Rect {!
int x, y, w, h;!
public:!
virtual void setPos(int x, int y);!
....!
};!
!
class Name { !
string name;!
public:!
virtual void setName(const string&);!
....!
};!
!
class NamedRect : public Rect, public Name {!
public:!
NamedRect(const string& s, int x, int y, int w, int h)!
: Rect(x,y,w,h), Name(s) {}!
};!
Principe
- la classe hérite des variables et méthodes de toutes ses superclasses
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 195
Collisions de noms
class Rect {!
int x, y, w, h;!
public:!
virtual void draw();!
....!
};!
!
class Name { !
string x;!
public:!
virtual void draw();!
....!
};!
!
class NamedRect : public Rect, public Name {!
public:!
....!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 196
Collisions de noms
class Rect {!
int x, y, w, h;!
public:!
virtual void draw();!
....!
};!
!
class Name { !
string x;!
public:!
virtual void draw();!
....!
};!
!
class NamedRect : public Rect, public Name {!
public:! Solutions
void draw() override {!
• redéfinir les méthodes
Rect::draw();!
Name::draw();!
concernées
}! ou
// ou bien!
• choisir la méthode héritée
using Rect::draw();!
...!
avec using
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 197
Héritage en diamant
class Shape {!
int x, y, w, h;!
public:!
virtual void draw();!
....!
};!
!
class Rect : public Shape { !
....!
};!
!
class Name : public Shape { !
....!
};!
!
class NamedRect : public Rect, public Name {!
public:!
....!
};!
Problème
• la classe de base (Shape) est dupliquée car elle est héritée des deux côtés
• fait rarement sens !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 198
Héritage en diamant
class Shape {!
int x, y, w, h;!
public:!
virtual void draw();!
....!
};!
!
class Rect : public Shape { !
....!
};!
!
class Name : public Shape { !
....!
};!
!
class NamedRect : public Rect, public Name {!
public:!
....!
};!
• c'est ce que fait Java 8 avec les default methods des interfaces
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 199
Héritage virtuel
class Shape {!
int x, y, w, h;!
public:!
virtual void draw();!
....!
};!
!
class Rect : public virtual Shape { !
....!
};!
!
class Name : public virtual Shape { !
....!
};!
!
class NamedRect : public Rect, public Name {!
public:!
....!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 200
Classes imbriquées
class Car : public Vehicle {!
class Door { !
public: ! classe imbriquée!
virtual void paint();!
....!
};!
public:!
Car(string model, string color);!
...!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 201
Classes imbriquées (2)
class Car : public Vehicle {!
class Door { !
public: !
virtual void paint();!
....! problème: paint() n'a pas
};! accès à color !
public:!
Car(string model, string color);!
...!
};!
Java
– les méthodes des classes imbriquées ont automatiquement accès
aux variables et méthodes de la classe contenante
Pas en C++ !
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 202
Classes imbriquées (3)
class Car : public Vehicle {!
class Door {!
Car* car; ! pointe l'objet contenant!
public:!
Door(Car* car) : car(car) {} !
virtual void paint();!
....!
OK : paint() a accès à
};!
car->color!
Door leftDoor, rightDoor;!
string model, color; !
public:!
Car(string model, string color);!
...!
};!
Solution (rappel)
– pour « envoyer un message » à un objet il faut son adresse
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 203
Sérialisation
But
- transformer l'information en mémoire en une représentation externe
non volatile (et vice-versa)
Cas d’usage
- persistance : sauvegarde sur / relecture depuis un fichier
- transport réseau : communication de données entre programmes
Implémentation
- Java : en standard, mais spécifique à Java
- C/C++ : pas standard (pour les objets) mais diverses extensions :
• Cereal, Boost, Qt, Protocol Buffers (Google), OSC ...
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 204
Sérialisation binaire vs. texte
Sérialisation binaire Sérialisation au format texte
- objets stockés en binaire - tout est converti en texte
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 205
Ecriture/lecture d’objets (format texte)
Principe : définir des fonctions d'écriture polymorphiques
#include <iostream>!
!
class Vehicle {!
public:!
virtual void write(std::ostream & f);! ne pas oublier virtual !
virtual void read(std::istream & f);!
....!
};! chaîner les méthodes
!
class Car : public Vehicle {!
string model;!
int power;!
Fichier:
public: !
void write(std::ostream & f) override {! whatever\n écrit par!
whatever\n Véhicle!
Vehicule::write(f);!
f << model << ‘\n’ << power << ‘\n’;! Ferrari 599 GTO\n écrit!
}! 670\n par Car!
!
whatever\n
void read(std::istream & f) override {! whatever\n
Vehicule::read(f);! Smart Fortwo\n
f >> model >> power; ! 71\n
}!
....!
};!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 206
Lecture avec espaces
void read(std::istream & f) override {!
Fichier:
Vehicule::read(f);! whatever\n
f >> power >> model; ! whatever\n
}! Ferrari 599 GTO\n
! 670\n
Problème
whatever\n
whatever\n
Smart Fortwo\n
>> s’arrête au premier espace (‘ ‘, ‘\n’, ’\r’, ’\t’, ’\v’, ’\f’) 71\n
Solution
getline() : lit toute la ligne (ou jusqu'à un certain caractère)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 207
Classes polymorphes
Problème
- les objets ne sont pas tous du même type (mais dérivent d’un même type)
Vehicle
Motorcycle
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 208
Classes polymorphes
Solution
#include <iostream>!
écrire le nom de la classe
!
des objets dans le fichier class Vehicle {!
public:!
virtual std::string classname() const = 0;!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 209
Sauver des objects
passer vecteur par référence!
#include <fstream>!
!
bool saveAll(const std::string & filename, const std::vector<Vehicle *> & objects) {!
std::ostream f(filename);!
if (!f) {! vérifie que le !
cerr << "Can't open file " << filename << endl;! ficher est ouvert!
return false;!
}!
!
écrire la classe!
for (auto it : objects) {!
puis les attributs
f << it->classname();!
it->write(f); !
if (f.fail()) { ! erreur d'écriture
cerr << "Write error in " << filename << endl;!
return false;!
} !
} !
return true;!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 210
Lire des objets passer vecteur par référence!
sinon il est recopié !
if (f.fail()) { !
erreur de lecture
cerr << "Read error in " << filename << endl;!
delete obj;!
return false;!
} !
else objects.push_back(obj);!
}!
return true;!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 211
stringstream
Flux de caractères
- fonctionne de la même manière que istream et ostream!
#include <string>!
#include <iostream>!
#include <sstream>!
void foo(const string& str) {!
std::stringstream ss(str);!
int power = 0; !
string model;!
ss >> power >> model;!
cout << "Vehicle: power:" << power << " model: " << model << endl;!
!
Vehicle * obj = new Car();!
obj->read(ss);!
}!
!
foo("670 \n Ferrari-599-GTO");!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 212
Compléments
Améliorations
- meilleur traitement des erreurs
- gérer les pointeurs et les conteneurs
=> utiliser Boost, Cereal, etc.
JSON
- JavaScript Object Notation
- commode pour les échanges textuels
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 213
Client / serveur
Cas typique
- un serveur de calcul
- des interfaces utilisateur pour interagir avec le serveur
- cas du TP INF224
Principe source:
maieutapedia.org
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 214
Client / serveur
Dialogue synchrone Dialogue asynchrone
- le client émet une requête et bloque - le client vaque à ses occupations après
jusqu'à réception de la réponse l'émission de la requête
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 215
Sockets
Principe
- canal de communication bi-directionnel entre 2 programmes
source: inetdoc.net
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 216
Sockets
Protocole UDP Protocole TCP
- Datagram sockets (type SOCK_DGRAM) - Stream sockets (type SOCK_STREAM)
- rapide mais des paquets peuvent être
- flux d'octets entre 2 programmes, pas de
perdus ou arriver dans le désordre paquets perdus et toujours dans l'ordre
• ex : HTTP, TP INF224
source: inetdoc.net
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 217
Sockets
Connexion TCP persistante
- le client est toujours connecté au serveur
- solution utilisée dans le TP
source: wikipedia
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 218
Mémoire et sécurité
#include <stdio.h> // en langage C!
#include <stdbool.h>!
#include <string.h>!
!
#define CODE_SECRET "1234"!
! Questions :
int main(int argc, char**argv) !
{! Que fait ce programme ?
bool is_valid = false;!
char code[5];! Est-il sûr ?
!
printf("Enter password: ");!
scanf("%s", code);!
!
if (strcmp(code, CODE_SECRET) == 0) !
is_valid = true;!
!
if (is_valid) !
printf("Welcome dear customer ;-)\n");!
else !
printf("Invalid password !!!\n");!
!
return 0;!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 219
Mémoire et sécurité
Avec LLVM sous MacOSX 10.7.1 :
#include <stdio.h> // en langage C!
#include <stdbool.h>! !
#include <string.h>!
Enter password: 111111!
!
#define CODE_SECRET "1234"! Welcome dear customer ;-)!
!
!
int main(int argc, char**argv) !
{! Adresses: !
bool is_valid = false;!
0x7fff5fbff98a 0x7fff5fbff98f
char code[5];!
! 0x7fff5fbff998 0x7fff5fbff900!
printf("Enter password: ");!
scanf("%s", code);!
!
if (strcmp(code, CODE_SECRET) == 0) !
Débordement de chaînes :
is_valid = true;! technique typique de piratage
!
if (is_valid) ! informatique
printf("Welcome dear customer ;-)\n");!
else !
printf("Invalid password !!!\n");!
!
printf("Adresses: %p %p %p %p\n",!
code, &is_valid, &argc, argv);!
!
return 0;!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 220
Mémoire et sécurité
#include <iostream> // en C++!
#include <string>!
!
static const string CODE_SECRET{"1234"};!
!
int main(int argc, char**argv) !
{! string au lieu de char*
bool is_valid = false;!
string code;!
!
cout << "Enter password: ";!
cin >> code;! pas de débordement : !
! taille allouée automatiquement
if (code == CODE_SECRET) is_valid = true;!
else is_valid = false;!
!
if (is_valid) !
cout << "Welcome dear customer ;-)\n";!
else ! rajouter une clause else!
cout << "Invalid password !!!\n";! ne mange pas de pain !
!
et peut eviter des erreurs
return 0;!
}!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 221
Mélanger C et C++
De préférence
• tout compiler (y compris les .c) avec compilateur C++
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 222
Mélanger C et C++
Dans un header C
• pouvant indifféremment être inclus dans un .c ou un .ccp, écrire :
#ifdef __cplusplus!
extern "C" {!
#endif!
!
void foo(int i, char c, float x);!
int goo(char* s, char const* s2);!
!
#ifdef __cplusplus!
}!
#endif!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 223
Librairies statiques et dynamiques
Librairies statiques
- code binaire inséré dans l’exécutable
à la compilation
- extension .a (Unix)
Librairies dynamiques
- code binaire chargé dynamiquement
à l’exécution
- .dll (Windows), .so (Linux), dylib (Mac)
- avantages :
- programmes moins gros et plus rapides (moins de swap si DLL partagée)
- inconvénient :
- nécessite la présence de la DLL (cf. licences et versions)
(cf. variable LD_LIBRARY_PATH (ou équivalent) sous Unix)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 224
Arithmétique des pointeurs
adressse
de tab
Tableaux
int tab[10];
tab[k] == *(tab + k) // valeur du kième élément du tableau
&tab[k] == tab + k // adresse du kième élément du tableau
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 225
Tableaux et pointeurs
adressse
de tab
sizeof(tab) vaut 10
sizeof(p) dépend du processeur (4 si processeur 32 bits)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 226
Manipulation de bits
Opérateurs
& ET
| OU inclusif
^ OU exclusif
<< décalage à gauche
>> décalage à droite
~ complément à un
int n = 0xff, m = 0;
m = n & 0x10;
m = n << 2; /* équivalent à: m = n * 4 */
Attention: ne pas confondre & avec && (et logique) ni | avec | | (ou logique)
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 227
Orienté objet en C
C C++
typedef struct { class User {
char* name; char* name; // en fait utiliser string
long id; long id;
} User; public:
User (const char* name, int id);
User* createUser (const char* name, int id); virtual ~User( );
void destroyUser (User*); virtual void setName(const char* name);
void setUserName (User*, const char* name); virtual void print() const;
void printUser (const User*); ....
.... };
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 228
Orienté objet en C
typedef struct User {! User* newUser() {!
int a;! User* p = (User*) malloc(sizeof(User));!
void (*print) (const struct User*);! p->a = 0;!
} User;! p->print = printUser;!
! return p;!
! }!
typedef struct Player { // subclass! !
User base;! !
int b;! Player* newPlayer() {!
} Player;! Player* p = (Player*) malloc(sizeof(Player));!
! p->base.a = 0;!
! p->base.print = printPlayer; // cast nécessaire!
void print(const User* u) {! p->b = 0;!
(u->print)(u);! return p;!
}! }!
! !
! !
void printUser(const User *u) {! int main() {!
printf("printUser a=%d \n", u->a);! Player* p = newPlayer();!
}! p->base.a = 1;!
! p->b = 2;!
! print(p);!
void printPlayer(const Player *u) {! !
printf("printPlayer a=%d b=%d\n", ! !
u->base.a, u->b);! // NB: en fait il faudrait partager les pointeurs!
}! // de fonctions de tous les objets d’une même !
//classe via une vtable!
Eric Lecolinet - Télécom ParisTech - Programmation orientée objet et autres concepts illustrés en C++11 229