C vers C++
version support : 2.0
Introduction
• C++ a été développé dans les années 1980 par
Bjarne Stroustrup
• http://www2.research.att.com/~bs/homepage....
Introduction
• Principales fonctionnalités ajoutées par rapport au langage C
– déclaration reconnue comme une instruction ...
Hello, world
• L'exemple incontournable
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
inclus...
Programmation orientée objet
• L'objet
– propriétés (variables de l'objet)
– méthodes (fonctions manipulant les variables ...
Conventions de nommage
• Utilisez des noms de fonction, de variable qui
permettent une auto-documentation du code
• Attent...
Type C++
• Les types du langage C sont repris par C++
– entiers (nb octets donné à titre indicatif)
• char : 1 octet
• sho...
C++11 – pointeur NULL
• Le mot clé nullprt a été ajouté comme
constante du langage
– constante de type nullptr_t
• non con...
Quelques différences avec C
• La bibliothèque standard C++ définit de nouvelles
classes et templates.
– nous utiliserons r...
Quelques différences avec C
• Exemple d'utilisation de string et vector
#include <iostream>
#include <vector>
#include <st...
Affichage à l'écran
• Opérateur d'insertion <<
– surcharge de l'opérateur de décalage à gauche
• un même symbole peut dési...
Lecture au clavier
• Opérateur d'extraction >>
– surcharge de l'opérateur de décalage vers la droite
• cin représente l'en...
C++11 – Inférence de type
• Nouvelle sémantique pour le mot clé auto
– indiquait la classe de stockage
• comportement par ...
C++11 – Inférence de type
• Le mot clé decltype permet de typer une
variable à partir du type d'une expression
int number ...
C++11 – boucle "foreach"
• L'instruction for permet de parcourir un
intervalle
– tableau, conteneurs de la STL définissant...
C++11 – type array
• Type std::array<TYPE,TAILLE>
– inclure <array>
• Possède des méthodes
– size(), front(), back(), at()...
C++11 – énumérations fortement typées
• Utilisation de enum class ou enum struct
à la place de enum
– pas de conversion im...
Fonctions inline
• Une fonction inline donne la possibilité à C++
d'insérer le code sans créer de fonction
– pas de créati...
Fonctions inline
• En fonction des réglages du compilateur, les
fonctions peuvent être inline automatiquement
ou pas
inlin...
Fonctions inline
• Sous Visual Studio
– sur le projet faire clic droit puis propriétés
antislashn.org
C vers C++ 20
Les références
• Nouveauté notable de C++ par rapport à C
– ne doit pas être confondue avec la notion de pointeur
– le pas...
Les références
• Une référence doit être initialisée lors de sa
déclaration
– avec un objet (expression devant être une lv...
Passage d'arguments par référence
• En C les arguments sont passés par valeur
– il y a création sur la pile d'une nouvelle...
Passage d'arguments par référence
• La fonction classique d'échange permet d'illustrer
le passage par référence
void echan...
Retour de référence
• En C une fonction de la forme
– retourne la valeur de x
int f()
{
...
return x;
}
– retourne la vale...
Retour de référence
• En C++ une fonction peut retourner une référence
– dans ce cas l'expression f() est une référence ve...
Retour de référence
• Exemple
int & augmenter(int &x)
{
x += 10 ;
return x;
}
int main()
{
int i = 5;
retour-reference.cpp...
Retour de référence
• Ne pas retourner une référence à une variable
locale d'une fonction
– la variable locale est créée s...
Surcharge des fonctions
• C++ permet de surcharger les fonctions
– un même nom de fonction peut-être associé à
plusieurs f...
Surcharge des fonctions
• Le compilateur va générer 4 fonctions
– afficher_Fi, afficher_Fc, afficher_Fd,
afficher_FPc
• F ...
Surcharge des fonctions
• Appel de fonctions C par un programme C++
– soit une fonction C int f(int); est définie dans
une...
Surcharge des fonctions
• Pour choisir la fonction surchargée le compilateur utilise un
certain nombre de règles
1. il rec...
C++11 – fonctions lambda
• fonction anonyme
– fonction qui n'a pas de nom
– peut-être passée comme argument
• par exemple ...
C++11 – fonctions lambda
• Exemple
vector<int> nombres = {0,1,2,3,4,5,6,7,8,9};
for_each(nombres.begin(), nombres.end(), [...
C++11 – fonction lambda
• Il est possible d'affecter une lambda à une
variable
– de type std::function
• adaptateur généri...
C++11 – fonctions lambda
• Closure
– une fermeture est une fonction qui capture des
variables à l'extérieur de celle-ci
– ...
C++11 – fonctions lambda
• Exemples
int somme = 0;
auto add = [&somme](int a, int b){ somme=a+b; };
antislashn.org
C vers ...
C++11 – fonctions lambda
• Résumé de la syntaxe de capture
– [] : pas de variable externe
– [i,&j] : i capturée par valeur...
Arguments par défaut
• Il est possible d'affecter une valeur par défaut à
tout ou partie des paramètres d'une fonction
voi...
Opérateur de portée ::
• L'opérateur de portée :: permet d'utiliser une
variable globale masquée par une variable locale
i...
Ordres des déclarations
• Contrairement au C, les déclarations peuvent être
effectuées lors de la première utilisation d'u...
Allocation dynamique de mémoire
• En C l'allocation de mémoire est effectuée par un
malloc, la libération de mémoire par f...
Allocation dynamique de mémoire
• L'opérateur new permet d'initialiser un objet de
type défini :
int * pi = new int(10);
•...
Allocation dynamique de mémoire
• Allocation à une adresse imposée
• Gestionnaire de manque de mémoire
– il faut vérifier ...
Allocation dynamique de mémoire
• Exemple de handler
void gestionnaire()
{
cout << "Plus de memoire" << endl;
system("PAUS...
Emploi de const
• const int i = 10;
– définit une valeur qui restera constante
• i est de type const int
– en C++ le compi...
Emploi de const
• int i;
const int *p = &i;
– p est un pointeur qui pointe sur un objet constant
• l'initialisation de p n...
Emploi de const
• Paramètre de type const
– si on fournit un argument de type const à une fonction, le
compilateur génère ...
Forçage de type
• En C++ il est illégal de convertir un pointeur
void* en un autre type sans forçage explicite du
type
int...
Forçage de type
• Comme en C
– un pointeur vers un objet non constant ou vers une
fonction peut être affecté à un pointeur...
Forçage de type
• C++ introduit de nouveaux opérateurs de forçage
de type :
– static_cast
– dynamic_cast
–– const_cast
– r...
Forçage de type
• static_cast
– permet d'effectuer toute conversion standard, si les types sont
cohérents entre eux
• type...
Forçage de type
• const_cast
– permet la conversion d'une entité const en entité
non const
const int i = 10;
double j = 10...
Structure
• C++ conserve la notion de structure du C
– en C++ la structure réunie des données et des
fonctions membres
• l...
Structure
• Exemple
struct identite
{
char * nom;
void afficher()
{
cout << "Nom : " << nom << endl;
}
}; pas besoin de pr...
Structure
• Déclaration des fonctions membres
– une fonction membre définie à l'intérieur de la
structure est par défaut i...
Structure
• La notion d'encapsulation demande à ce que
– les données membres soient privées
• il faut donc des fonctions m...
Classe
• Une classe est déclarée par le mot clé class
• La notion de classe ne diffère que sur un seul
point de celle de s...
Classe
• Exemple
class Point
{
int x,y;
public :
void afficher();
void init(int,int);
};
x et y sont privées :
mise en pla...
Classe - .h et .cpp
• Le fichier .h contient
– les propriétés de la classe
– les prototypes des méthodes
• si une méthode ...
Classe - .h et .cpp
• Il est fréquent qu'une classe A contienne un
attribut de type classe B et que cette même
classe B co...
Classe - .h et .cpp
class B;
class A{
B *ptrB;
void foo();
};
A.h
#include "A.h"
#include "B.h"
void A::foo(){
A& a = ptrB...
Classe – conventions de nommage
• Une spécification de développement est un choix
consensuel
– établi des règles communes ...
Classe – conventions de nommage
• Les noms donnés à vos classes, méthodes, …
forment votre vocabulaire de développement
• ...
Classe – règles de conception
• Encapsulation des propriétés
– par défaut elle sont privées
– mise en place de méthodes d'...
Classe – règles de conception
• Exemple issu de Qt – style
– garder à l'esprit que si le code est au moins écrit une
fois,...
Classe – membres de classe
• Les variables de la classe sont appelées
– propriétés (attributs en UML)
• Les fonctions de l...
Classe – membres de classe
• Le modificateur const peut être utilisé pour
class Point{
int x,y;
public:
Point(int i, int j...
Classe – membres de classe
• Une méthode constante ne pourra invoquer que
des méthodes constantes
class Point {
int x,y;
p...
Classe – membres de classe
• Une propriété peut être déclarée mutable pour
pouvoir être modifiée par une méthode const
– A...
Classe – membres de classe
• Les propriétés représentent l'état d'une instance
– en mémoire il y à deux objets de type Poi...
Classe – membres de classe statique
• Certaines propriétés peuvent être partagées par
toutes les instances d'une classe
– ...
Classe – membres de classe statique
• Une méthode statique ne peut utiliser que des
membres statiques
– elle "existe" en d...
Classe – membre de classe statique
• Exemple de membre de classe statique de type
tableau
class A{
private:
static int tab...
Classe – pointeur this
• Le pointeur this représente l'instance en cours
• Lors de l'appel des méthodes d'une classe, ce
p...
Fonctions et classes amies
• Une fonction qui n'est pas membre d'une classe n'a
pas accès aux membres privées de cette cla...
Fonctions et classes amies
• Exemple
class Point
{
private :
int x,y;
public :
void init(int,int);
friend void afficher(Po...
Fonctions amies
• Certaines surcharges d'opérateurs peuvent être
effectuées via des fonctions amies
– simplification du co...
Constructeurs et destructeur
• Un constructeur est une fonction membre d'une
classe
– le nom de la fonction est le même qu...
Constructeurs et destructeurs
• Les objets sont construits dans l'ordre
d'apparition des déclarations
– attention : dans c...
Constructeur par défaut
• Il ne possède pas d'arguments
– prototype : nom_classe()
• Il est appelé automatiquement
– lors ...
Constructeur par défaut
• Exemple (extrait) class Point
{
private :
int x,y;
public :
void afficher();
Point();
};
Point::...
Constructeur par défaut
• ATTENTION
Trouvez l'erreur !!!
class Point
{
private :
int x,y;
public :
void afficher();
Point(...
Constructeur par défaut
• ATTENTION
Point p1();
– déclare le prototype de la
fonction p1
– ne génère pas d'erreur à la
cla...
Destructeur
• Le destructeur est appelé lorsqu'un objet sort de
sa portée
– prototype : ~nom_classe();
• pas de type de re...
Constructeurs de conversion
• Une classe peut comporter plusieurs
constructeurs de conversion
– prototype :
• nom_classe(l...
Constructeurs de conversion
• Exemple (extrait) :
class Point
{
private :
int x,y;
public :
void afficher();
Point();
Poin...
Constructeurs de conversion
• Note
Point p(3,4);
et
Point p = Point(3,4);
peuvent conduire à un code généré différent, dan...
Constructeurs de conversion
• Note
– Point p = (Point)6.3; provoquera un
transtypage et l'appel du constructeur Point(int)...
Constructeurs de conversion
• Un constructeur à un seul argument définit une
conversion de type qui est appelée implicitem...
Constructeurs de conversion
• Exemple de conversion ambiguë (extrait)
class Z{
public:
Z(){};
};
class X{
public:
X(Z z){}...
Constructeurs de conversion
• Exemple avec explicit (extrait)
class Z{
public:
Z(){};
};
class X{
public:
X(Z z){};
}; la ...
Constructeur de copie
• Il est appelé implicitement
– lors d'une initialisation de la forme :
• T idBis = id; où T est le ...
Constructeur de copie
• Deux prototypes possibles
• nom_classe (nom_classe &);
• nom_classe (const nom_classe &);
– préfér...
Constructeur de copie
• Exemple (extrait) :
class Point
{
private :
int x,y;
public :
void afficher();
Point();
Point(cons...
Tableau d'objets
• La syntaxe du C est utilisable pour initialiser des
tableaux d'instances de classe
– la classe doit pos...
Tableau d'objets
• Lors de l'allocation mémoire par new[] le
constructeur par défaut est appelé
– le delete[] invoquera le...
Liste d'initialisation
• C++ apporte un nouveau mécanisme
d'initialisation des membres d'une classe par un
construteur
– l...
Liste d'initialisation
• Exemple (extrait)
class A{
int i;
double d;
char c;
public :
A(int k) : i(k), d(18.06), c('a') {}...
Liste d'initialisation
• La liste d'initialisation est utilisée pour
l'initialisation d'une instance de classe qui elle-
m...
Liste d'initialisation
• Lors d'une déclaration B b; le compilateur va :
– allouer l'espace pour b
– initialiser le membre...
Liste d'initialisation
• Exemple (extrait)
– en rencontrant a(20) le compilateur va initialiser a.i
en invoquant le constr...
Liste d'initialisation
• Initialisation d'une propriété constant ou
référence
– seule la liste d'initialisation permet d'i...
C++11 – Délégation de constructeur
• En C++ un constructeur ne peut pas appeler un
autre constructeur de cette même classe...
C++11 – Délégation de constructeur
• Exemple de code
class Point{
int x;
int y;
antislashn.org
C vers C++ 105
public :
Poi...
Opérateur de conversion
• Un constructeur peut être appelé pour effectuer
une conversion de type
• exemple : Point p = (Po...
Opérateur de conversion
• Exemple
class Point{
int x,y;
public:
Point(int x, int y) {this->x = x; this->y = y; }
operator ...
Objets constants
• Si un objet est déclaré constant, les fonctions
membres ne sont plus utilisables
– les fonctions membre...
Propriété constante
• Une propriété peut-être déclarée const
– comment l'initialiser ?
• Membre de classe non statique et ...
Propriété constante
• Membre de classe statique et constant
– initialisation au moment du chargement du
programme
class X
...
Surcharge des opérateurs
• C++ permet de surcharger les opérateurs
– par exemple utiliser l'opérateur + pour "additionner"...
Surcharge des opérateurs
• Syntaxe générale pour la surcharge d'un
opérateur :
– type operator op(types des opérandes);
• ...
Surcharge des opérateurs
• De manière générale, si un opérateur est défini au
niveau de la classe il attend un paramètre d...
Surcharge des opérateurs
• Surcharge au niveau de la classe
– définition dans la classe
– l'objet de classe qui invoque es...
Surcharge des opérateurs
• Surcharge des opérateurs ++ et --
– la définition des opérateurs préfixés est standard
– la déf...
Surcharge des opérateurs
• Surcharge de l'opérateur d'affectation =
– par défaut fait une copie de surface de la classe
cl...
Surcharge des opérateurs
• Surcharge de l'opérateur d'indexation []
– ne peut qu'être qu'un membre de classe
– considéré c...
Surcharge des opérateurs
• Exemple de surcharge de l'opérateur [] (extrait)
class Tableau{
int *tab;
int taille;
public:
....
Surcharge des opérateurs
• Surcharge de l'opérateur d'appel de fonction ()
– nommé aussi foncteur ou objet fonction
– uniq...
Surcharge des opérateurs
• Exemple de foncteurs
class Inferieur{
public:
bool operator()(int i, int j) { return i < j; }
b...
Surcharge des opérateurs
• Opérateur de conversion – rappel
• syntaxe : operator type () {…}
– le type retourné doit corre...
Surcharge des opérateurs
• Les surcharges utilisables et leurs syntaxes sont
résumés sur le site Wikipedia
– http://en.wik...
C++11 – Rvalue Reference
• Une lvalue est une expression possédant un nom
et qui reste en mémoire un certain temps
– une v...
C++11 – Rvalue Reference
• Introduction d'une sémantique de déplacement
(move)
– en C++ il n'y a pas de manière générique ...
C++11 – Constructeur de déplacement
• Extrait de code
class MyContainer{
int nSize;
char* pString;
public:
MyContainer(MyC...
C++11 – Opérateur de déplacement
• Extrait de code
class MyContainer{
int nSize;
char* pString;
public:
MyContainer& opera...
C++11 - Sémantique de déplacement
• Par rapport aux constructeur et opérateur de
copie – extrait de code
...
public:
MyCon...
C++11 - Sémantique de déplacement
• Fonction utilitaires de la bibliothèque utility
– std::move()
• retourne une référence...
Les patrons
• Si plusieurs fonctions sont définies de la même
façon et ne diffèrent que par les types
d'arguments, le déve...
Patron de fonction
• Les types des arguments ne sont pas fixés et sont
considérés eux-mêmes comme des paramètres
– syntaxe...
Patron de classe
• Il peut arriver que plusieurs classes soient
définies de manières identiques, aux types près
– un patro...
Patron de classe
• Le compilateur générera les classes nécessaires
• Un patron de classe est entièrement codé dans le
fich...
Patron de classe
• Déclarations et définitions séparées
template <typename T> class Tableau{
T tab[2];
public:
Tableau(T x...
Patron de classe
• Il est possible de préciser un paramètre template
par défaut
template <typename T, typename Y=int> clas...
typename
• typename est utilisé pour introduire un type
générique
– class peut aussi être utilisé
• typename sert aussi à ...
Membres statiques
• Donnée statique
– la classe contient la déclaration de la donnée statique
– la définition de la donnée...
Membres statiques
• Fonction statique
– n'a pas accès aux membres non statiques
– le pointeur this n'est pas passé à la fo...
Héritage
• Syntaxe de base
class classe_derivee : type_protection classe_base {…};
– le type de protection définit l'acces...
Héritage
• La classe dérivée hérite de l'ensemble des
membres de la classe de base
– les membres privés sont hérités mais ...
Héritage
• Empreinte mémoire
– la classe B dérive de la classe A
class A{
char ta[256];
};
class B : public A{
heritage-1....
Héritage
• Exemple
class Vehicule{
char *marque;
public:
Vehicule(){marque = "INCONNU"; }
Vehicule(char * marque){this->ma...
Héritage – sous-typage
• Conversion de classe dérivée en classe de base
– la conversion est implicite dès que cela est néc...
Héritage – forçage vers la classe dérivée
• Il est illicite de convertir un type de base vers un
type dérivé.
• Un pointeu...
Héritage – forçage vers la classe dérivée
• Exemple
class Vehicule{
char *marque;
public:
Vehicule(){marque = "INCONNU"; }...
Héritage
• L'accès à un membre peut être désignés par son nom ou par son nom
complètement qualifié.
– si le nom du membre ...
Héritage – les constructeurs
• Chaque fois qu'un constructeur d'une classe
dérivée est appelé, le constructeur de la class...
Héritage – les constructeurs
• Cas général
– si un constructeur de la classe dérivée est appelé
(autre que le constructeur...
Héritage – les constructeurs
• Exemple : cas général
class A{
public:
A(){ cout << "A()n";}
A(int i){ cout << "A(int i)n";...
Héritage – les constructeurs
• Cas du constructeur de copie
– lorsqu'une classe ne possède pas de constructeur par
copie l...
Héritage – les constructeurs
• Exemple : constructeur de copie
class A{
public:
A(){ cout << "A()n";}
A(const A &a){ cout ...
Héritage - template
• Un template peut hériter d'un autre template
• Une classe peut hériter d'un template
template <typen...
Dérivation et opérateur d'affectation
• Similaire au constructeur de copie
– soit b2 = b1; où b1 et b2 sont des instances
...
Dérivation et opérateur d'affectation
class A{
public:
A(){cout << "++ CONSTRUCTEUR A()" << endl;}
A(const A &a){cout << "...
Polymorphisme
• Un des principes du polymorphisme est qu'une classe dérivée
est compatible avec sa classe de base.
– là où...
Polymorphisme
• Selon que l'on applique cette conversion sur des objets ou
des pointeurs la conversion est effectuée diffé...
Polymorphisme
• Convertir un pointeur vers Carre vers un pointeur
vers Figure ne fait perdre aucune information
– l'instan...
Polymorphisme
• Exemple
– seul l'appel de l'affichage d'un Carre par un objet de
type Carre fonctionne !!!
– il faut disti...
Polymorphisme
• Par défaut la détermination du membre accédé à travers un
pointeur ou une référence est fait durant la com...
Fonctions virtuelles
• Types statiques et dynamiques
class B {};
class D : public B {};
int main()
{
D d;
B b = d;
B *pb =...
Fonctions virtuelles
class Figure{
public:
virtual void afficher(){
cout << "A CODER" << endl;
}
};
class Carre : public F...
Fonctions virtuelles
• La création d'une classe polymorphe implique l'initialisation
d'un pointeur vptr vers une vtable de...
Fonctions virtuelles
• Un objet n'est pas typé tant qu'il n'est pas
complètement construit
– un constructeur ne peut pas ê...
Destructeur virtuel
class A{
public:
A(){ cout << "++ CONSTRUCTEUR A()" << endl;}
~A(){ cout << "-- DESTRUCTEUR ~A()" << e...
Classe abstraite
• Des fonctions peuvent être purement virtuelles
– pas d'implémentation fournie
– présente le vocabulaire...
Classe abstraite
• Exemple class Figure{
public:
virtual void afficher() =0 ;
};
class Point : public Figure{
int x,y;
pub...
Héritage multiple
• En C++ une classe peut hériter de plusieurs
classes de base
– lors de l'initialisation de la classe B,...
Héritage multiple
• Si les classes A1 et A2 sont elles même dérivées
d'une même classe de base, des ambigüités
peuvent app...
Héritage multiple
• Les membres d'une classe possèdent une portée
– par dérivation de classe ou imbrication d'une classe d...
Héritage multiple
• Exemple
class A1{
int i;
public:
void f(int i) { cout << "A1::f(int)n"; }
};
class A2{
int j;
heritage...
Héritage multiple
• Empreinte mémoire
class A1{
char ta1[100];
};
class A2{
char ta2[100];
};
class B : public A1, public ...
Héritage multiple
• Soit le schémas d'héritage
class A {...};
class B1 : public A {...};
class B2 : public A {...};
class ...
Héritage multiple
• Sans déclaration virtual
class A{
char a[100];
};
class B1:public A{
char b1[100];
};
char a[100]
inst...
Héritage multiple
• Le code devient alors
class A {...};
class B1 : virtual public A {...};
class B2 : virtual public A {....
Héritage multiple
• Avec déclaration virtual
class A{
char a[100];
};
class B1:virtual public A{
char b1[100];
};
char a[1...
Classe – forme générale
• Forme générale
– un constructeur par défaut
• allocation de certaines parties de l'objet
– un de...
Classe – forme générale
• Héritage et forme générale
– classe de base T respectant la forme générale
• destructeur virtuel...
Identification dynamique du type
• Le coût du polymorphisme est une indirection
supplémentaire pour chaque appel de méthod...
Identification dynamique de classe
• Opérateur dynamic_cast
– syntaxe : dynamic_cast<type>(expression)
– permet la convers...
Identification dynamique de classe
• Exemple sur dynamic_cast
class A{
virtual void foo(){}
};
class B1:public A{};
class ...
Identification dynamique de classe
• Opérateur typeid
– permet de connaitre le véritable type d'un objet désigné par un
po...
Pointeur sur membre de classe
• Il est courant de manipuler des fonctions au
travers de pointeurs
– mécanisme du C
– trans...
Pointeur sur membre de classe
• Pour un objet donné, il est toujours possible de
référencer par pointeur une donnée
– sous...
Pointeur sur membre de classe
• Mais il peut être utile de pouvoir manipuler des
notions plus abstraites
– pointer sur une...
Pointeur sur membre de classe
• Pointeur sur une donnée membre
– déclaration
• type classe::*pointeur;
– initialisation
• ...
Pointeur sur membre de classe
• Exemple de pointeur sur une donnée membre
using namespace std;
class A{
public:
int i;
A(i...
Pointeur sur membre de classe
• Pointeur sur une fonction membre
– déclaration
• type_retour (class::*pointeur)(liste_type...
Pointeur sur membre de classe
• Exemple de pointeur sur une fonction membre
class A{
public:
int i;
A(int j){i=j;}
int dou...
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Passer du langage C au langage C++
Prochain SlideShare
Chargement dans…5
×

Passer du langage C au langage C++

1 395 vues

Publié le

Passer du langage C au langage C++.
La connaissance du langage C est un pré-requis obligatoire.

Publié dans : Logiciels
0 commentaire
0 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

  • Soyez le premier à aimer ceci

Aucun téléchargement
Vues
Nombre de vues
1 395
Sur SlideShare
0
Issues des intégrations
0
Intégrations
5
Actions
Partages
0
Téléchargements
71
Commentaires
0
J’aime
0
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Passer du langage C au langage C++

  1. 1. C vers C++ version support : 2.0
  2. 2. Introduction • C++ a été développé dans les années 1980 par Bjarne Stroustrup • http://www2.research.att.com/~bs/homepage.html • C++ est un langage normalisé par l'ISO ISO/CEI 14882:1998– ISO/CEI 14882:1998 – ISO/CEI 14882:2003 – ISO/CEI 14882:2011 (C++11) – ISO/CEI 14882:2014 (mise à jour de la norme) • C++ est un autre langage que C antislashn.org C vers C++ 2
  3. 3. Introduction • Principales fonctionnalités ajoutées par rapport au langage C – déclaration reconnue comme une instruction (repris en C99) – opérateurs new et delete – type de donnée bool – mot clé const (repris en C99) – espaces de nom – classes et tout ce qui est lié à la POO– classes et tout ce qui est lié à la POO – surcharge des opérateurs – gestion des exceptions – identification des types à l'exécution • RTTI : run-time type identification – commentaire // (repris en C99) – fonction inline (repris en C99) – paramètres par défaut dans les fonctions – les références antislashn.org C vers C++ 3
  4. 4. Hello, world • L'exemple incontournable #include <iostream> using namespace std; int main(int argc, char *argv[]) { inclusion du fichier d'entête, le ".h" n'est pas nécessaire (sauf pour C) utilisation d'espace de nommage pour éviter les collisions de nom type de retour obligatoire hello.cpp antislashn.org C vers C++ 4 { cout << "Hello, world" << endl; system("PAUSE"); return EXIT_SUCCESS; } objet de type ostream représentant le flux de sortie opérateur d'insertion return facultatif si absent un return 0 est effectué
  5. 5. Programmation orientée objet • L'objet – propriétés (variables de l'objet) – méthodes (fonctions manipulant les variables de l'objet) • Concepts de base – encapsulation • il n'est pas possible d'accéder aux données de l'objet• il n'est pas possible d'accéder aux données de l'objet – uniquement par l'intermédiaire des méthodes – classe • généralisation de la notion de type • structure de données + fonctions – héritage • permet de créer une nouvelle classe sur une classe existante – polymorphisme • possibilité de traiter de la même manière des objets de type différents antislashn.org C vers C++ 5
  6. 6. Conventions de nommage • Utilisez des noms de fonction, de variable qui permettent une auto-documentation du code • Attention aux conventions de pré-fixage des noms de variables par leur type • int intNb; – que devient le préfixe si le type vient à évoluer ? • int est remplacé par long, pour rester cohérent il faut que intNb devienne longNb antislashn.org C vers C++ 6
  7. 7. Type C++ • Les types du langage C sont repris par C++ – entiers (nb octets donné à titre indicatif) • char : 1 octet • short int (ou short) : 2 octets • int : 4 octets • long int (ou long) : 4 octetslong int (ou long) : 4 octets • long long : 8 octets • peuvent être signed, ou unsigned – types flottants • float : 8 bits exposants, 23 bits mantisse (4 octets) • double : 11 bits exposants, 52 bits mantisse (8 octets) • long double : 15 bits exposants, 64 bits mantisse (12 octets) – type booléen • bool : valeurs true ou false antislashn.org C vers C++ 7
  8. 8. C++11 – pointeur NULL • Le mot clé nullprt a été ajouté comme constante du langage – constante de type nullptr_t • non convertible vers un entier • convertible vers void*• convertible vers void* – assignable à tout type de pointeur • en C++ il est interdit d'assigner un void* à un pointeur d'un type différent antislashn.org C vers C++ 8
  9. 9. Quelques différences avec C • La bibliothèque standard C++ définit de nouvelles classes et templates. – nous utiliserons régulièrement • la classe string – représente une chaîne de caractères– représente une chaîne de caractères • la classe vector – peut-être vu comme un tableau dynamique – le type des éléments doit être précisé lors de la déclaration • ces classes seront vues plus en détail plus tard antislashn.org C vers C++ 9
  10. 10. Quelques différences avec C • Exemple d'utilisation de string et vector #include <iostream> #include <vector> #include <string> using namespace std; int main(){ vector-string.cpp inclusions nécessaires construction antislashn.org C vers C++ 10 int main(){ string nom = "toto"; vector<int> v; for(int i=0 ; i < 5 ; i++) v.push_back(i); cout << nom << endl; for(int i=0 ; i < v.size() ; i++) cout << v[i] << " "; cout << endl; } ajout dynamique d'éléments d'un vecteur de int
  11. 11. Affichage à l'écran • Opérateur d'insertion << – surcharge de l'opérateur de décalage à gauche • un même symbole peut désigner plusieurs opérateurs distincts – l'opérande de droite est envoyé vers le flux– l'opérande de droite est envoyé vers le flux – opérateur associatif de droite vers la gauche • permet d'enchainer les affichages – de nombreuses options et opérateurs permettent de formater la sortie antislashn.org C vers C++ 11
  12. 12. Lecture au clavier • Opérateur d'extraction >> – surcharge de l'opérateur de décalage vers la droite • cin représente l'entrée standard – instance de la classe istream cout << "Entrez un nombre : "; cin >> nb; – instance de la classe istream – l'opérateur >> est associatif de gauche à droite • un séparateur quelconque (espace, tabulation,…) est utilisé pour l'analyse – n'est pas recueilli – de nombreuses options et opérateurs sont disponibles antislashn.org C vers C++ 12 cin >> nb >> nom;
  13. 13. C++11 – Inférence de type • Nouvelle sémantique pour le mot clé auto – indiquait la classe de stockage • comportement par défaut • auto était rarement utilisé – depuis C++11 auto prend la place du type dans la– depuis C++11 auto prend la place du type dans la déclaration de variable • le type sera alors celui de la rvalue • la variable de type auto doit donc être initialisée lors de la déclaration antislashn.org C vers C++ 13
  14. 14. C++11 – Inférence de type • Le mot clé decltype permet de typer une variable à partir du type d'une expression int number = 1; auto y = number; decltype(y) z; y et z seront de type int • auto peut être utilisé pour le type de retour d'une fonction – le type est précisé après la parenthèse fermante antislashn.org C vers C++ 14 int aa; auto foo() -> decltype(aa){ return aa++; } le type de retour sera int
  15. 15. C++11 – boucle "foreach" • L'instruction for permet de parcourir un intervalle – tableau, conteneurs de la STL définissant les fonctions membres begin() et end() antislashn.org C vers C++ 15 int tab[5] = {1, 2, 3, 4, 5}; for (int &x: tab) { x *= 2; }
  16. 16. C++11 – type array • Type std::array<TYPE,TAILLE> – inclure <array> • Possède des méthodes – size(), front(), back(), at(), empty(), … – les crochets [] sont toujours utilisables antislashn.org C vers C++ 16 const int TAILLE = 5; array<int,TAILLE> tab = {1,2,3,4,5}; for(int nb : tab){ cout << nb << endl; }
  17. 17. C++11 – énumérations fortement typées • Utilisation de enum class ou enum struct à la place de enum – pas de conversion implicite vers le type int • conversion explicite seulement – accès aux éléments par l'opérateur de portée ::– accès aux éléments par l'opérateur de portée :: antislashn.org C vers C++ 17 enum class State{STOP,START}; State s = State::STOP;
  18. 18. Fonctions inline • Une fonction inline donne la possibilité à C++ d'insérer le code sans créer de fonction – pas de création de fonction, pas de copie sur la pile – exemple : inline int carre(int x) {return x*x;}inline int carre(int x) {return x*x;} – évite les effets de bords des définitions de macro du C #define carre(x) ((x)*(x)) – n'est qu'une requête au compilateur, celui-ci peut l'ignorer et créer une vraie fonction – ne peut pas faire l'objet d'une compilation séparée – ne peut pas être manipulée par un pointeur vers fonction antislashn.org C vers C++ 18
  19. 19. Fonctions inline • En fonction des réglages du compilateur, les fonctions peuvent être inline automatiquement ou pas inline int max(int a, int b){return a>b?a:b;} int main(void) antislashn.org C vers C++ 19 int main(void) { int i,j,k; cin >> j >> k; i = max(j,k); cout << i << endl; } _TEXT SEGMENT ?max@@YAHHH@Z PROC ; max, COMDAT ; _a$ = ecx ; _b$ = eax ; 5 : int max(int a, int b){return a>b?a:b;} 00000 3b c8 cmp ecx, eax 00002 7e 02 jle SHORT $LN4@max 00004 8b c1 mov eax, ecx $LN4@max: 00006 c3 ret 0 ?max@@YAHHH@Z ENDP ; max
  20. 20. Fonctions inline • Sous Visual Studio – sur le projet faire clic droit puis propriétés antislashn.org C vers C++ 20
  21. 21. Les références • Nouveauté notable de C++ par rapport à C – ne doit pas être confondue avec la notion de pointeur – le passage par adresse (contenu d'un pointeur) n'est pas le passage par référence – une référence est un alias d'un objet en mémoire– une référence est un alias d'un objet en mémoire – syntaxe : type & identificateur = expression; antislashn.org C vers C++ 21 int main(){ int i = 30; int &ri = i; ri += 10; cout << i << " == " << ri << endl; cout << "@i = " << &i << endl; cout << "@ri = " << &ri << endl; } reference.cpp
  22. 22. Les références • Une référence doit être initialisée lors de sa déclaration – avec un objet (expression devant être une lvalue) • int &i = 10; n'est pas valide – dépend du compilateur et version de C++– dépend du compilateur et version de C++ • const int &i = 10; est valide – on ne peut pas déclarer un tableau de références • int i, j; int &tab[] = {i,j}; est illégal – en pratique les références sont utilisées dans le cadre de passage de paramètres et retour de fonction antislashn.org C vers C++ 22
  23. 23. Passage d'arguments par référence • En C les arguments sont passés par valeur – il y a création sur la pile d'une nouvelle variable – copie de l'argument passé • dans le cas d'un pointeur il y a bien copie du contenu du pointeur, c'est-à-dire de l'adresse de l'objet pointé – la valeur initiale de la variable passée n'est pas– la valeur initiale de la variable passée n'est pas affectée par les modification dans la fonction • Le passage par référence crée un nouveau nom pour la variable passée à la fonction – les modifications dans la fonction impacterons la valeur de la variable initiale antislashn.org C vers C++ 23
  24. 24. Passage d'arguments par référence • La fonction classique d'échange permet d'illustrer le passage par référence void echanger(int &i, int &j) { int t = i; i=j; j=t; } reference-echanger.cpp – les valeurs de a et b ont bien été échangées antislashn.org C vers C++ 24 } int main() { int a = 10; int b = 30; cout << "Avant a == " << a << " et b == " << b << endl; echanger(a,b); cout << "Apres a == " << a << " et b == " << b << endl; }
  25. 25. Retour de référence • En C une fonction de la forme – retourne la valeur de x int f() { ... return x; } – retourne la valeur de x • il y a création sur la pile d'une variable à laquelle est affectée la valeur de x • l'expression f() est une rvalue, non pas une lvalue – on ne peut pas écrire f() = expression; antislashn.org C vers C++ 25
  26. 26. Retour de référence • En C++ une fonction peut retourner une référence – dans ce cas l'expression f() est une référence vers la int &f() { ... return x; } – dans ce cas l'expression f() est une référence vers la variable x • c'est-à-dire une lvalue – on peut écrire f() = expression; • de nombreuses fonctions ou templates C++ retournent des références – operator<<, operator>>, etc… antislashn.org C vers C++ 26
  27. 27. Retour de référence • Exemple int & augmenter(int &x) { x += 10 ; return x; } int main() { int i = 5; retour-reference.cpp – l'expression augmenter(i) est une référence pour la variable i du main • i vaudra 30 antislashn.org C vers C++ 27 int i = 5; augmenter(i) += 15; cout << i << endl; system("PAUSE"); }
  28. 28. Retour de référence • Ne pas retourner une référence à une variable locale d'une fonction – la variable locale est créée sur la pile et sa durée de vie est celle de la fonction • comme il ne faut pas retourner l'adresse d'une variable locale lorsque l'on travaille par pointeur • comme il ne faut pas retourner l'adresse d'une variable locale lorsque l'on travaille par pointeur • Attention aux conversions de type – si i avait été de type char l'appel de la fonction aurait généré une conversion de type, donc une variable temporaire aurait été créée sur la pile qui n'est pas la variable i antislashn.org C vers C++ 28
  29. 29. Surcharge des fonctions • C++ permet de surcharger les fonctions – un même nom de fonction peut-être associé à plusieurs fonctions – le compilateur génère plusieurs fonctions de noms différents en tenant compte du type des paramètresdifférents en tenant compte du type des paramètres • la signature de la fonction • le type de retour n'est pas utilisé • le modificateur const est utilisé – le choix de la fonction à appeler est déterminé par le type des arguments antislashn.org C vers C++ 29
  30. 30. Surcharge des fonctions • Le compilateur va générer 4 fonctions – afficher_Fi, afficher_Fc, afficher_Fd, afficher_FPc • F pour fonction, P pour pointeur, R pour référence, C pour constant génèrerait– f(const char &) génèrerait f_FRCc antislashn.org C vers C++ 30 void afficher(int i) { cout << "int : " << i << endl; } void afficher(char c) { cout << "char : " << c << endl; } void afficher(double d) { cout << "double : " << d << endl; } void afficher(char * s) { cout << "string : " << s << endl; } surcharge-fonctions.cpp
  31. 31. Surcharge des fonctions • Appel de fonctions C par un programme C++ – soit une fonction C int f(int); est définie dans une librairie C – la simple déclaration de son prototype est insuffisante • le compilateur lui donnera un nom différent, tenant compte• le compilateur lui donnera un nom différent, tenant compte des paramètres • l'éditeur de lien ne pourra pas la retrouver – la déclaration doit être faite par • extern "C" int f(int); • si plusieurs fonctions : – extern "C" {déclarations et inclusions} antislashn.org C vers C++ 31
  32. 32. Surcharge des fonctions • Pour choisir la fonction surchargée le compilateur utilise un certain nombre de règles 1. il recherche une version avec correspondance exacte de type entre les arguments et les paramètres 2. il essaie d'appliquer les règles habituelles de promotion numérique 3. il essaie d'appliquer les règles de conversion standard sur les3. il essaie d'appliquer les règles de conversion standard sur les pointeurs et références (classes et classes dérivées) 4. il essaie d'appliquer les règles de conversion définies par le développeur (vues plus loin) 5. il vérifie s'il existe une version à un nombre variable d'arguments • Au cours de ces étapes, si une ambigüité est détectée le compilateur lève une erreur antislashn.org C vers C++ 32
  33. 33. C++11 – fonctions lambda • fonction anonyme – fonction qui n'a pas de nom – peut-être passée comme argument • par exemple à la fonction std::for_each, à la place d'un foncteurfoncteur – syntaxe : [](paramètres) -> return_type { corps; } • [] : captures • si return_type n'est pas précis il est déduit par le compilateur antislashn.org C vers C++ 33
  34. 34. C++11 – fonctions lambda • Exemple vector<int> nombres = {0,1,2,3,4,5,6,7,8,9}; for_each(nombres.begin(), nombres.end(), [](int element) { cout << element << endl; liste d'initialisation C++11 antislashn.org C vers C++ 34 } ); lambda [](int a, int b) -> int{ return a+b; }; type de retour
  35. 35. C++11 – fonction lambda • Il est possible d'affecter une lambda à une variable – de type std::function • adaptateur générique de fonction permettant d'appeler une cible appelablecible appelable – cible pour laquelle operator() est défini – on fournit alors le type de retour et la liste des arguments » void s'il n'y a pas de type de retour • ou de type auto antislashn.org C vers C++ 35 std::function<int (int,int)> add1 = [](int a, int b){ return a+b; }; auto add2 = [](int a, int b){ return a+b; }; type de retour suivi du type des paramètres
  36. 36. C++11 – fonctions lambda • Closure – une fermeture est une fonction qui capture des variables à l'extérieur de celle-ci – il faut préciser les variables à capturer entre [] – la capture est effectuée– la capture est effectuée • par référence – les éventuelles modifications affecterons la variable capturée • par valeur – c'est une copie de la variable capturée, les modifications n'affecterons pas la variable capturée antislashn.org C vers C++ 36
  37. 37. C++11 – fonctions lambda • Exemples int somme = 0; auto add = [&somme](int a, int b){ somme=a+b; }; antislashn.org C vers C++ 37 int somme = 0; auto add = [somme](int a, int b){ somme=a+b; };
  38. 38. C++11 – fonctions lambda • Résumé de la syntaxe de capture – [] : pas de variable externe – [i,&j] : i capturée par valeur, j par référence – [&] : toutes les variables externes sont capturées par référenceréférence – [=] : toutes les variables externes sont capturées par valeur – [&,x] : x est capturée par valeur, les autres variables externes sont capturées par référence – [=,&x] : x est capturée par référence, les autres variables externes sont capturées par valeur antislashn.org C vers C++ 38
  39. 39. Arguments par défaut • Il est possible d'affecter une valeur par défaut à tout ou partie des paramètres d'une fonction void afficher(int i, int b=0, int c=3){…} – l'affectation par défaut peut remplacer certaines surcharges explicites d'une fonction antislashn.org C vers C++ 39
  40. 40. Opérateur de portée :: • L'opérateur de portée :: permet d'utiliser une variable globale masquée par une variable locale int x = 10; int main() { int x = 20; cout << "x local == " << x <<endl; antislashn.org C vers C++ 40 cout << "x local == " << x <<endl; cout << " x global == " << ::x << endl; } surcharge-fonctions.cpp
  41. 41. Ordres des déclarations • Contrairement au C, les déclarations peuvent être effectuées lors de la première utilisation d'une variable int main() { int x = 10; x est visible dans toute la fonction main i est déclaré seulement pour antislashn.org C vers C++ 41 int x = 10; for(int i = 0 ; i<10 ; i++) { cout << i << endl; } if(int i=x-11 > 0) cout << "i > 0" << endl; else cout << "i <= 0" << endl; cout << i << endl; } i est déclaré seulement pour le bloc for i est déclaré seulement pour le bloc if - else erreur de compilation car pas de déclaration pour ce i declarations.cpp
  42. 42. Allocation dynamique de mémoire • En C l'allocation de mémoire est effectuée par un malloc, la libération de mémoire par free • En C++ l'allocation de mémoire est effectuée par new, la libération par delete antislashn.org C vers C++ 42 int main() { int *pi; int *ti; pi = new int; ti = new int[50]; delete pi; delete [] ti; } affectation de l'adresse d'un int affectation de l'adresse d'un tableau de 50 int libération pour un int libération pour un tableau de int new-simple.cpp
  43. 43. Allocation dynamique de mémoire • L'opérateur new permet d'initialiser un objet de type défini : int * pi = new int(10); • Lorsque new retourne l'adresse d'une instance de classe ou de structure, cette initialisation n'estclasse ou de structure, cette initialisation n'est possible que si un constructeur adéquat a été prévu. • Il n'est pas possible d'initialiser un tableau alloué par new antislashn.org C vers C++ 43
  44. 44. Allocation dynamique de mémoire • Allocation à une adresse imposée • Gestionnaire de manque de mémoire – il faut vérifier que new (comme malloc) ne retourne pas la valeur null int *pi; int *ti; pi = new ((int *)0X0FFF) int; ti = new (pi+10) int[50]; new-simple.cpp valeur null – un gestionnaire peut être mis en place pour tout retour de null par new • le rôle de ce gestionnaire est de tenter de libérer de la mémoire – à la fin de l'exécution du gestionnaire, la main est donnée de nouveau au new » sauf si dans le gestionnaire il y a une instruction type exit(…) • le gestionnaire (handler) ne doit attendre aucun paramètre et ne retourne rien • l'adresse du handler est passée à la fonction set_new_handler antislashn.org C vers C++ 44
  45. 45. Allocation dynamique de mémoire • Exemple de handler void gestionnaire() { cout << "Plus de memoire" << endl; system("PAUSE"); exit(1); } mise en place du gestionnaire antislashn.org C vers C++ 45 int main() { set_new_handler(gestionnaire); int *pi; int *ti; pi = new int; ti = new int[1000000000]; delete pi; delete [] ti; } demande trop importante mise en place du gestionnaire new-handler.cpp
  46. 46. Emploi de const • const int i = 10; – définit une valeur qui restera constante • i est de type const int – en C++ le compilateur peut ne pas définir un objet en mémoiremémoire – doit être initialisé à la définition • par une expression constante, connue à la compilation – un objet const est de classe static antislashn.org C vers C++ 46
  47. 47. Emploi de const • int i; const int *p = &i; – p est un pointeur qui pointe sur un objet constant • l'initialisation de p n'est pas obligatoire – i peut être modifié directement, pas par *p • int i; int *const p = &i;int *const p = &i; – p est un pointeur constant qui pointe sur un objet i • l'initialisation est obligatoire • p ne peut pas varier • i peut être modifié directement ou via *p • const int * const p = &i; – p est un pointeur constant qui pointe sur un objet constant • initialisation obligatoire • p ne peut pas varier, *p n'est pas une lvalue antislashn.org C vers C++ 47
  48. 48. Emploi de const • Paramètre de type const – si on fournit un argument de type const à une fonction, le compilateur génère une erreur • certains compilateurs génèrent un warning – il faut définir le paramètre de la fonction comme const– il faut définir le paramètre de la fonction comme const • Nous reviendrons sur le modificateur const lors de l'étude des classes antislashn.org C vers C++ 48 void f(const int &i) { cout << i << endl; } const int j = 20; int main() { f(j); system("PAUSE"); }
  49. 49. Forçage de type • En C++ il est illégal de convertir un pointeur void* en un autre type sans forçage explicite du type int *p = malloc(20); • n'est pas légal en C++• n'est pas légal en C++ int *p = (int *) malloc(20); • est légal en C++ antislashn.org C vers C++ 49
  50. 50. Forçage de type • Comme en C – un pointeur vers un objet non constant ou vers une fonction peut être affecté à un pointeur void* – l'adresse d'un objet constant ne peut pas être affecté à un pointeur non constant sans forçage de typeà un pointeur non constant sans forçage de type antislashn.org C vers C++ 50 const int j = 10; int * q1 = &j; // ILLEGAL void *q2 = &j; // ILLEGAL void *q3 = (int *)&j; // LEGAL mais dangereux const void *q4 = &j; // CORRECT const.cpp
  51. 51. Forçage de type • C++ introduit de nouveaux opérateurs de forçage de type : – static_cast – dynamic_cast –– const_cast – reinterpret_cast – syntaxe : • opérateur <type> (expression); antislashn.org C vers C++ 51
  52. 52. Forçage de type • static_cast – permet d'effectuer toute conversion standard, si les types sont cohérents entre eux • type vers type • pointeur vers pointeur • référence vers référence – ne permet pas de retirer le modificateur const– ne permet pas de retirer le modificateur const • dynamic_cast – effectue des vérifications à l'exécution – utilisé pour le polymorphisme • sera vu plus loin antislashn.org C vers C++ 52 const int i = 10; char c = static_cast <char> (3.14); // CORRECT int *p = static_cast <int *> (&i); // ILLEGAL int *q = static_cast <int *> (20000); // ILLEGAL forcage-type.cpp on force l'adresse pointée par q
  53. 53. Forçage de type • const_cast – permet la conversion d'une entité const en entité non const const int i = 10; double j = 10; int *p = const_cast <int *> (&i); // CORRECT forcage-type.cpp • reinterpret_cast – permet de forcer le typage entre types différents – ne permet pas de retirer le modificateur const antislashn.org C vers C++ 53 int *p = const_cast <int *> (&i); // CORRECT int q = const_cast <int> (j); // ILLEGAL const int i = 10; int *p = reinterpret_cast <int *> (&i); // ILLEGAL int *q = reinterpret_cast <int *> (2000); // CORRECT forcage-type.cpp
  54. 54. Structure • C++ conserve la notion de structure du C – en C++ la structure réunie des données et des fonctions membres • la syntaxe d'accès reste la même : – point . pour un accès direct – flèche -> pour un accès par pointeur– flèche -> pour un accès par pointeur – trois niveaux de visibilité sont prévus • public : visibilité en tout point du programme – visibilité par défaut sur les structures • private : visibilité par les fonctions membres et amies • protected : visibilités par les fonctions membres et les structures dérivées antislashn.org C vers C++ 54
  55. 55. Structure • Exemple struct identite { char * nom; void afficher() { cout << "Nom : " << nom << endl; } }; pas besoin de préfixer par antislashn.org C vers C++ 55 }; int main() { identite id; id.nom = "Toto"; id.afficher(); system("PAUSE"); } pas besoin de préfixer par struct structure-identite-1.cpp
  56. 56. Structure • Déclaration des fonctions membres – une fonction membre définie à l'intérieur de la structure est par défaut inline – une fonction membre peut-être définie à l'extérieur de la structurede la structure antislashn.org C vers C++ 56 struct identite { char * nom; void afficher(); }; void identite::afficher() { cout << "Nom : " << nom << endl; } déclaration dans la structure définition par le nom complètement qualifié de la fonction en utilisant l'opérateur de portée structure-identite-2.cpp
  57. 57. Structure • La notion d'encapsulation demande à ce que – les données membres soient privées • il faut donc des fonctions membres publiques pour les lire et les modifier – les accesseurs / mutateur, ou getter / setter – les fonctions membres publiques présentent l'interface– les fonctions membres publiques présentent l'interface d'utilisation de la structure – l'initialisation de la structure est effectuée à l'aide de fonctions adaptées : les constructeurs • En C++ la structure est peu utilisée car les classes sont généralement plus adaptées – par défaut les membres sont privés antislashn.org C vers C++ 57
  58. 58. Classe • Une classe est déclarée par le mot clé class • La notion de classe ne diffère que sur un seul point de celle de structure : les membres sont privés par défaut – encapsulation des données– encapsulation des données • Ordre de déclaration des classes – les classes doivent être déclarées avant d'être employée – une déclaration incomplète peut-être utilisée • syntaxe : class X; – forward declaration (déclaration anticipée) antislashn.org C vers C++ 58
  59. 59. Classe • Exemple class Point { int x,y; public : void afficher(); void init(int,int); }; x et y sont privées : mise en place d'une fonction d'initialisation Point-1.cpp antislashn.org C vers C++ 59 void Point::afficher() { cout << "Point en (" << x << "," << y << ")" << endl; } void Point::init(int x, int y) { Point::x = x; this->y = y; } utilisation du pointeur this this est l'adresse de l'objet qui invoque la fonction utilisation de l'opérateur de portée d'initialisation
  60. 60. Classe - .h et .cpp • Le fichier .h contient – les propriétés de la classe – les prototypes des méthodes • si une méthode est définie dans le .h, elle est considérée comme inlinecomme inline • Le fichier .cpp contient les définitions des méthodes antislashn.org C vers C++ 60
  61. 61. Classe - .h et .cpp • Il est fréquent qu'une classe A contienne un attribut de type classe B et que cette même classe B contienne un attribut de type A – attribut ou argument de fonction • On se retrouve très vite avec un problème• On se retrouve très vite avec un problème d'inclusion cyclique • L'utilisation d'une forward declaration dans le .h permet de résoudre ce problème – tant que l'on utilise un pointeur ou une référence le compilateur à juste besoin de connaitre l'existence de la classe antislashn.org C vers C++ 61
  62. 62. Classe - .h et .cpp class B; class A{ B *ptrB; void foo(); }; A.h #include "A.h" #include "B.h" void A::foo(){ A& a = ptrB->getA(); } A.cpp class A; B.h #include "A.h" #include "B.h" B.cpp Pointeur vers B pas besoin du .h antislashn.org C vers C++ 62 class B{ A &refA; public: B(A &a); A& getA(); }; #include "B.h" B::B(A &a):refA(a){}; A& B::getA(){return refA;} #include "A.h" class C{ A a; }; C.h #include "C.h" C.cpp Référence vers A pas besoin du .h Propriété de type A le compilateur à besoin du constructeur A() inclusion du .h
  63. 63. Classe – conventions de nommage • Une spécification de développement est un choix consensuel – établi des règles communes de développement – améliore la compréhension du code par l'équipe • Une convention de nommage doit-être mise en• Une convention de nommage doit-être mise en place – fait partie des spécifications de développement – doit permettre une auto-documentation du code – doit avoir un choix approuvé des noms de variables, fonctions, classe, … antislashn.org C vers C++ 63
  64. 64. Classe – conventions de nommage • Les noms donnés à vos classes, méthodes, … forment votre vocabulaire de développement • Une normalisation est importante – exemple : • le nom d'une classe commence par une majuscule • le nom d'une méthode, variable, propriété par une minuscule • utilisation de l'intercapitalisation – camelcase antislashn.org C vers C++ 64
  65. 65. Classe – règles de conception • Encapsulation des propriétés – par défaut elle sont privées – mise en place de méthodes d'accès • exemple de convention : setXxx(…) getXxxx() • Donner des noms explicites aux méthodes• Donner des noms explicites aux méthodes • Généraliser le vocabulaire – utiliser le polymorphisme • nommer une méthode d'affichage afficher() quelque soit la classe antislashn.org C vers C++ 65
  66. 66. Classe – règles de conception • Exemple issu de Qt – style – garder à l'esprit que si le code est au moins écrit une fois, il sera lu de nombreuses fois • il devra être compréhensible et auto-documenté • ainsi le constructeur suivant est peut intuitif à écrire et à lire• ainsi le constructeur suivant est peut intuitif à écrire et à lire • il peut être avantageusement remplacé par antislashn.org C vers C++ 66 QSlider *slider = new QSlider(12, 18, 3, 13, Qt::Vertical, 0, "volume"); QSlider *slider = new QSlider(Qt::Vertical); slider->setRange(12, 18); slider->setPageStep(3); slider->setValue(13); slider->setObjectName("volume");
  67. 67. Classe – membres de classe • Les variables de la classe sont appelées – propriétés (attributs en UML) • Les fonctions de la classe sont appelées – méthodes (opérations en UML) • Les constructeurs sont des méthodes spécifiques qui sont appelées lors de la construction de la classeappelées lors de la construction de la classe – on parle aussi d'instanciation – sera vu en détail plus tard • Les destructeurs sont des méthodes spécifiques qui sont appelées avant la désallocation de l'objet – sera vu en détail plus tard • L'ensemble des méthodes et propriétés forme les membres de la classe antislashn.org C vers C++ 67
  68. 68. Classe – membres de classe • Le modificateur const peut être utilisé pour class Point{ int x,y; public: Point(int i, int j){x=i; y=j;} int getX(){ return x;} int getY(){ return y;} void setX(int x){this->x = x;} void setY(int y){this->y = y;} }; propriétés privées constructeur accesseurs pour les propriétés privées • Le modificateur const peut être utilisé pour indiqué qu'une méthode ne modifiera pas les propriétés de la classe antislashn.org C vers C++ 68 class Point { int x,y; public: Point(int i, int j){x=i; y=j;} int getX()const { return x;} int getY()const { return y;} void setX(int x){this->x = x;} void setY(int y){this->y = y;} }; les getteurs sont const le compilateur vérifiera le contrat
  69. 69. Classe – membres de classe • Une méthode constante ne pourra invoquer que des méthodes constantes class Point { int x,y; public: Point(int i, int j){x=i; y=j;} int getX() { return x;} erreur de compilation car getX() n'est pas const antislashn.org C vers C++ 69 int getX() { return x;} int getY() { return y;} void setX(int x){this->x = x;} void setY(int y){this->y = y;} void afficher() const {cout << "x == " << getX() << endl;} }; getX() n'est pas const
  70. 70. Classe – membres de classe • Une propriété peut être déclarée mutable pour pouvoir être modifiée par une méthode const – ATTENTION : le contrat annoncé par la méthode n'est plus respecté déclaration de x mutable antislashn.org C vers C++ 70 class Point { int mutable x; int y; public: Point(int i, int j){x=i; y=j;} int getX() { return x;} int getY() { return y;} void setX(int x){this->x = x;} void setY(int y){this->y = y;} void verifier() const {if(x==0) x=10;} }; déclaration de x mutable méthode const pas d'erreur de compilation sur l'affectation
  71. 71. Classe – membres de classe • Les propriétés représentent l'état d'une instance – en mémoire il y à deux objets de type Point possédant int main(){ Point p1(1,2); Point p2(10,20); } – en mémoire il y à deux objets de type Point possédant chacun leur état antislashn.org C vers C++ 71 p1:Point x 1 y 2 p2:Point x 10 y 20
  72. 72. Classe – membres de classe statique • Certaines propriétés peuvent être partagées par toutes les instances d'une classe – propriétés statiques class Point { static int compteur; propriété partagée par antislashn.org C vers C++ 72 static int compteur; int x; int y; public: Point(int i, int j){x=i; y=j; compteur++;} static int getNbPoints() { return compteur;} }; int Point::compteur = 0; int main(){ Point p1(1,2); Point p2(10,20); cout << Point::getNbPoints() << endl; } propriété partagée par toutes les instances initialisation de la propriété statique méthode statique utilisable sans instancier la classe invocation de la méthode statique
  73. 73. Classe – membres de classe statique • Une méthode statique ne peut utiliser que des membres statiques – elle "existe" en dehors de toute instance p1:Point antislashn.org C vers C++ 73 p1:Point x 1 y 2 p2:Point x 10 y 20 compteur 2
  74. 74. Classe – membre de classe statique • Exemple de membre de classe statique de type tableau class A{ private: static int tabInt[]; public: static int* getTabInt() {return tabInt;} static int getNbElements(); tableau_statique.h antislashn.org C vers C++ 74 static int getNbElements(); }; int A::tabInt[] = {1,2,3,10,20,30}; int A::getNbElements(){return sizeof(tabInt)/sizeof(tabInt[0]);} int main(){ A a; for(int i=0 ; i<a.getNbElements() ; i++) cout << a.getTabInt()[i] << endl; }
  75. 75. Classe – pointeur this • Le pointeur this représente l'instance en cours • Lors de l'appel des méthodes d'une classe, ce pointeur est passé comme premier paramètre – pointeur "caché" • la méthode est converti en • Le pointeur this n'est pas passé aux méthodes statiques antislashn.org C vers C++ 75 void setY(int y){this->y = y;} void setY(Point *const this, int y){this->y = y;}
  76. 76. Fonctions et classes amies • Une fonction qui n'est pas membre d'une classe n'a pas accès aux membres privées de cette classe. • Cette contrainte peut être levée en rendant publique les membres privées de la classe auprès de certaines fonctions – mot-clé friend– mot-clé friend – déclaration des fonctions amies dans la classe – des classes peuvent-être déclarées comme classes amies • Ceci ne devrait-être qu'une pratique exceptionnelle – des designs patterns permettent de conserver l'encapsulation • visiteur, commande, … antislashn.org C vers C++ 76
  77. 77. Fonctions et classes amies • Exemple class Point { private : int x,y; public : void init(int,int); friend void afficher(Point); friend class Ligne; déclaration de la fonction amie déclaration d'une classe amie Point-2.cpp antislashn.org C vers C++ 77 friend class Ligne; }; void afficher(Point p) { cout << "Point en (" << p.x << "," << p.y << ")" << endl; } class Ligne { public : void afficher(Point p1, Point p2) { cout << "Ligne depuis (" << p1.x << "," << p1.y << ") et (" << p2.x << "," << p2.y << ")" << endl; } }; utilisation des membres privés
  78. 78. Fonctions amies • Certaines surcharges d'opérateurs peuvent être effectuées via des fonctions amies – simplification du codage et accès à tous les membres – la surcharge de l'opérateur d'insertion << permet de définir comment une instance est insérée dans un fluxdéfinir comment une instance est insérée dans un flux antislashn.org C vers C++ 78 class Point{ int x,y; public: void init(int,int); friend ostream& operator<<(ostream &o,const Point &p); }; ostream& operator<<(ostream &o,const Point &p){ o << "Point en (" << p.x << "," << p.y << ")" << endl; return o; } … Point-3.cpp
  79. 79. Constructeurs et destructeur • Un constructeur est une fonction membre d'une classe – le nom de la fonction est le même que la classe – le constructeur n'a pas de type de retour (pas même void) – il peut y avoir plusieurs constructeurs– il peut y avoir plusieurs constructeurs • constructeur par défaut • constructeur de copie • constructeurs de conversion • Le destructeur est une fonction membre d'une classe dont le nom est celui de la classe préfixe par tilde (~) – appelé automatiquement lorsque l'objet est détruit – n'attend pas de paramètre, n'a pas de type de retour antislashn.org C vers C++ 79
  80. 80. Constructeurs et destructeurs • Les objets sont construits dans l'ordre d'apparition des déclarations – attention : dans certaines configuration l'ordre d'appel des constructeurs des variables globales ou statiques n'est que partiellement défini en C++n'est que partiellement défini en C++ • il peut varier d'un build à l'autre – cf. C++ faq-lite [10.11] [10.12] – cf. Google Style Guide "Static and Global Variables" • L'ordre d'appel des destructeurs est inverse de l'ordre d'appel des constructeurs • C++ garantit l'appel du destructeur antislashn.org C vers C++ 80
  81. 81. Constructeur par défaut • Il ne possède pas d'arguments – prototype : nom_classe() • Il est appelé automatiquement – lors de la définition d'un objet • <classe> identificateur;<classe> identificateur; – lors d'une allocation dynamique par new • <classe> * pointeur; • Si aucun constructeur n'est défini, le compilateur en fournit un par défaut – ATTENTION : dès qu'un constructeur est défini, ce constructeur par défaut n'est plus fournit • il faut alors le fournir explicitement antislashn.org C vers C++ 81
  82. 82. Constructeur par défaut • Exemple (extrait) class Point { private : int x,y; public : void afficher(); Point(); }; Point::Point() { x=10; prototype du constructeur par défaut définition du constructeur Point-4.cpp antislashn.org C vers C++ 82 x=10; y=20; } … int main() { Point p; Point * pt = new Point(); p.afficher(); pt->afficher(); delete pt;} définition du constructeur par défaut objet de type Point alloué sur la pile objet de type Point alloué sur le tas (les parenthèses sont facultatives) libération de la mémoire
  83. 83. Constructeur par défaut • ATTENTION Trouvez l'erreur !!! class Point { private : int x,y; public : void afficher(); Point(); }; Point::Point() { x=10; antislashn.org C vers C++ 83 x=10; y=20; } … int main() { Point p; Point p1(); Point * pt = new Point(); p.afficher(); pt->afficher(); delete pt; }
  84. 84. Constructeur par défaut • ATTENTION Point p1(); – déclare le prototype de la fonction p1 – ne génère pas d'erreur à la class Point { private : int x,y; public : void afficher(); Point(); }; Point::Point() { x=10;– ne génère pas d'erreur à la compilation – génère un warning à l'édition de liens si p1 n'est pas utilisé • génère une erreur si p1 est utilisé antislashn.org C vers C++ 84 x=10; y=20; } … int main() { Point p; Point p1(); Point * pt = new Point(); p.afficher(); pt->afficher(); delete pt; }
  85. 85. Destructeur • Le destructeur est appelé lorsqu'un objet sort de sa portée – prototype : ~nom_classe(); • pas de type de retour, pas même void • pas de paramètres• pas de paramètres – en général nécessaire s'il y eu allocation de mémoire par la classe • notion de composition – le destructeur peut-être invoqué par l'instance elle-même • z.~z(); antislashn.org C vers C++ 85 class Z{ int *tab; public: Z(int taille) {tab = new int[taille];} ~Z() { delete [] tab;} };
  86. 86. Constructeurs de conversion • Une classe peut comporter plusieurs constructeurs de conversion – prototype : • nom_classe(liste_de_type); – il utilise la liste des arguments passés pour construire– il utilise la liste des arguments passés pour construire un nouvel objet antislashn.org C vers C++ 86
  87. 87. Constructeurs de conversion • Exemple (extrait) : class Point { private : int x,y; public : void afficher(); Point(); Point(const Point &); Point(int); Point(int,int); }; Point::Point(int x) Deux prototypes de constructeurs de conversion Définition du premier constructeur de conversion Point-6.cpp antislashn.org C vers C++ 87 Point::Point(int x) { this->x = x; y = x; } Point::Point(int x, int y) { this->x = x; this->y = y; } int main() { Point p(50,47); Point * pt = new Point(6); … } Définition du second constructeur de conversion Création d'une instance sur la pile Création d'une instance sur le tas
  88. 88. Constructeurs de conversion • Note Point p(3,4); et Point p = Point(3,4); peuvent conduire à un code généré différent, dans lepeuvent conduire à un code généré différent, dans le second cas le compilateur peut créer un objet temporaire puis le recopier dans la variable p • Note – Point p = 16; appellera le constructeur de conversion Point(int) . antislashn.org C vers C++ 88
  89. 89. Constructeurs de conversion • Note – Point p = (Point)6.3; provoquera un transtypage et l'appel du constructeur Point(int) – Point p = (Point)6,4; provoquera un appel de Point(int) puis l'évaluation de l'expression 4Point(int) puis l'évaluation de l'expression 4 – C++ n'admet qu'un seul niveau de conversion par constructeur. Soient deux classes A et B ayant comme constructeurs • A(int); et B(A); • une définition telle que B b = 5; est illégale antislashn.org C vers C++ 89
  90. 90. Constructeurs de conversion • Un constructeur à un seul argument définit une conversion de type qui est appelée implicitement par le compilateur Point p = (Point)6.3; Point p = (Point) 'a'; – des effets de bords peuvent engendrer des ambigüités– des effets de bords peuvent engendrer des ambigüités qui rendent le programme incompilable – les conversion implicites peuvent être inhibées en utilisant explicit • Soyez cohérent et lisible dans l'appel des constructeurs antislashn.org C vers C++ 90
  91. 91. Constructeurs de conversion • Exemple de conversion ambiguë (extrait) class Z{ public: Z(){}; }; class X{ public: X(Z z){}; }; antislashn.org C vers C++ 91 }; class Y{ public: Y(Z z){}; }; void f(X x){ cout << "X" << endl; } void f(Y y){ cout << "Y" << endl; } int main() { Z z; f(z); } Deux conversions possibles, vers Y ou X le programme ne compile pas constructeurs-sans-explicit.cpp
  92. 92. Constructeurs de conversion • Exemple avec explicit (extrait) class Z{ public: Z(){}; }; class X{ public: X(Z z){}; }; la conversion vers la classe antislashn.org C vers C++ 92 }; class Y{ public: explicit Y(Z z){}; }; void f(X x){ cout << "X" << endl; } void f(Y y){ cout << "Y" << endl; } int main() { Z z; f(z); } la conversion vers la classe Y est inhibée la conversion est effectuée vers la classe X constructeurs-avec-explicit.cpp
  93. 93. Constructeur de copie • Il est appelé implicitement – lors d'une initialisation de la forme : • T idBis = id; où T est le nom de la classe et id une instance de la classe T – peut aussi s'écrire : T idBis(id); – lors du passage par copie d'un objet en argument d'une fonctionfonction – lorsqu'une fonction retourne un objet par valeur – lorsqu'un pointeur sur un objet reçoit une valeur par l'opérateur new • T *pt = new T(t); où t est une instance de T • S'il n'existe pas de constructeur de copie, C++ en fournit un permettant une copie superficielle de l'objet – copie bit à bit de l'objet, attention donc aux membres de type pointeur antislashn.org C vers C++ 93
  94. 94. Constructeur de copie • Deux prototypes possibles • nom_classe (nom_classe &); • nom_classe (const nom_classe &); – préférable car passage d'un argument const ou non • ATTENTION – il faut distinguer une création par copie– il faut distinguer une création par copie • T new_t = t; – d'une affectation • old_t = t; où old_t et t sont des objets déjà existants – il est alors fait appel à l'opérateur d'affectation (=) • par défaut, effectue une copie de surface, il faut donc souvent le redéfinir si certains membres sont des pointeurs antislashn.org C vers C++ 94
  95. 95. Constructeur de copie • Exemple (extrait) : class Point { private : int x,y; public : void afficher(); Point(); Point(const Point &); prototype constructeur de copie Point-5.cpp antislashn.org C vers C++ 95 Point(const Point &); }; … Point::Point(const Point &p) { x = p.x; y = p.y; } … int main() { Point p; Point p1 = p; … } définition du constructeur de copie Création d'une instance de Point par appel du constructeur de copie sur l'instance p
  96. 96. Tableau d'objets • La syntaxe du C est utilisable pour initialiser des tableaux d'instances de classe – la classe doit posséder les constructeurs adéquats class Point{ Point-7.cpp antislashn.org C vers C++ 96 class Point{ int x, y; public: Point(){x=y=0;} Point(int a) {x=y=a;} Point(int x, int y){this->x = x; this->y = y;} void afficher(){ cout << "Point en (" << x << "," << y << ")n";} }; int main(){ Point tp[] = {2,Point(),Point(3),Point(4,5)}; for(int i=0 ; i < sizeof(tp)/sizeof(tp[0]) ; i++) tp[i].afficher(); system("PAUSE"); }
  97. 97. Tableau d'objets • Lors de l'allocation mémoire par new[] le constructeur par défaut est appelé – le delete[] invoquera le destructeur … tableau_objets.cpp antislashn.org C vers C++ 97 … int main() { int NB = 5; Point *tp2 = new Point[NB]; delete [] tp2; } …
  98. 98. Liste d'initialisation • C++ apporte un nouveau mécanisme d'initialisation des membres d'une classe par un construteur – la liste d'initialisation – syntaxe :– syntaxe : nom_classe(liste_parametres) : liste_initialisateurs {corps} – l'ordre d'initialisation est celui dans lequel les membres apparaissent dans la classe et non pas l'ordre dans la liste antislashn.org C vers C++ 98
  99. 99. Liste d'initialisation • Exemple (extrait) class A{ int i; double d; char c; public : A(int k) : i(k), d(18.06), c('a') {}; }; liste-initialisation-1.cpp – l'appel du constructeur A a(20); initialisera les membres à • i == 20 • d == 18.06 • c == 'a' antislashn.org C vers C++ 99
  100. 100. Liste d'initialisation • La liste d'initialisation est utilisée pour l'initialisation d'une instance de classe qui elle- même comporte un objet d'une autre classe. • Dans l'exemple suivant : antislashn.org C vers C++ 100 class A{ int i; public : A() {i=0;} A(int k) {i=k;} }; class B{ int i; A a; public : B() {i=0;} };
  101. 101. Liste d'initialisation • Lors d'une déclaration B b; le compilateur va : – allouer l'espace pour b – initialiser le membre a en appelant le constructeur par défaut A() – initialiser le reste de b en appelant le constructeur par– initialiser le reste de b en appelant le constructeur par défaut B() • Comment fixer une valeur à l'instance a ? • sans que le compilateur appelle plusieurs fois le constructeur A() – utiliser une liste d'initialisation antislashn.org C vers C++ 101
  102. 102. Liste d'initialisation • Exemple (extrait) – en rencontrant a(20) le compilateur va initialiser a.i en invoquant le constructeur A(20) class A{ int i; public : • La liste d'initialisation permet d'optimiser le code antislashn.org C vers C++ 102 public : A() {i=0;} A(int k) {i=k;} }; class B{ int i; A a; public : B() : a(20) {i=0;} };
  103. 103. Liste d'initialisation • Initialisation d'une propriété constant ou référence – seule la liste d'initialisation permet d'initialiser ces propriétés antislashn.org C vers C++ 103 int j = 3; class A{ const int x; int &y; public : A() : x(7), y(j) {} A(int k) {x = k;} }; Illégal car x est constant et y est une référence A(int k):x(k),y(j) {} OK, liste d'intialisation
  104. 104. C++11 – Délégation de constructeur • En C++ un constructeur ne peut pas appeler un autre constructeur de cette même classe – duplication potentielle de code – utilisation d'une méthode privée pour factoriser le codecode • C++11 permet à un constructeur de déléguer le création d'une instance à un autre constructeur antislashn.org C vers C++ 104
  105. 105. C++11 – Délégation de constructeur • Exemple de code class Point{ int x; int y; antislashn.org C vers C++ 105 public : Point(int x, int y):x(x),y(y){} Point(int xy):Point(xy,xy){} };
  106. 106. Opérateur de conversion • Un constructeur peut être appelé pour effectuer une conversion de type • exemple : Point p = (Point)6.3; – ceci ne permet que les conversions dont le type cible est la classe elle-mêmeest la classe elle-même – il est possible de définir un opérateur de conversion dans une classe • syntaxe : operator type () {…} – le type retourné dans le code doit correspondre au type redéfini – pas d'indication du type retourné • il sera implicitement appelé chaque fois qu'une conversion sera nécessaire antislashn.org C vers C++ 106
  107. 107. Opérateur de conversion • Exemple class Point{ int x,y; public: Point(int x, int y) {this->x = x; this->y = y; } operator int() {return x+y;} }; définition de la conversion Point-8.cpp antislashn.org C vers C++ 107 int main() { Point p = Point(2,3); cout << p*2 << endl; system("PAUSE"); } vers int invocation de la conversion vers int
  108. 108. Objets constants • Si un objet est déclaré constant, les fonctions membres ne sont plus utilisables – les fonctions membres doivent être déclarées const • fait partie de la signature antislashn.org C vers C++ 108 class X { int i; public : X(int i) {this->i = i;} int doubler() const {return i*2;} }; int main() { const X x(3); cout << x.doubler() << endl; system("PAUSE"); } objet-constant.cpp
  109. 109. Propriété constante • Une propriété peut-être déclarée const – comment l'initialiser ? • Membre de classe non statique et constant – initialisation par une liste d'initialisationinitialisation par une liste d'initialisation antislashn.org C vers C++ 109 class X { const int i; public : X(int j) : i(j) {} int doubler() const {return i*2;} }; liste d'initialisation
  110. 110. Propriété constante • Membre de classe statique et constant – initialisation au moment du chargement du programme class X { objet-constant.cpp antislashn.org C vers C++ 110 { static const int i; public : X() {} int doubler() const {return i*2;} }; const int X::i = 3; int main() { const X x; cout << x.doubler() << endl; system("PAUSE"); } initialisation au chargement du programme
  111. 111. Surcharge des opérateurs • C++ permet de surcharger les opérateurs – par exemple utiliser l'opérateur + pour "additionner" deux instances de la classe Point – il est impossible de redéfinir les opérations prédéfinies en C++ – on ne peut pas créer de nouveaux opérateurs – les opérateurs suivants ne peuvent pas être surchargés– les opérateurs suivants ne peuvent pas être surchargés . :: ?: sizeof .* – les règles de précédences et d'associativités sont conservées – la syntaxe de la surcharge de certains opérateurs est soumise à des règles spécifiques • affectation = appel de fonction () indexation [] accès -> • ++ et -- doivent tenir compte des formes préfixées et suffixées antislashn.org C vers C++ 111
  112. 112. Surcharge des opérateurs • Syntaxe générale pour la surcharge d'un opérateur : – type operator op(types des opérandes); • ou op est l'opérateur à surcharger • Surcharge au niveau global• Surcharge au niveau global – définition en dehors de la classe – l'appel est équivalent à operator+(p1,p2); antislashn.org C vers C++ 112 Point operator+(Point &p1, Point &p2) { int x = p1.getX() + p2.getX(); int y = p1.getY() + p2.getY(); return Point(x,y); }
  113. 113. Surcharge des opérateurs • De manière générale, si un opérateur est défini au niveau de la classe il attend un paramètre de moins que le nombre d'opérandes – exemple Point-9.cpp antislashn.org C vers C++ 113 class Point{ int x,y; public: Point(int x, int y) {this->x = x; this->y = y; } void afficher(){ cout << "Point en (" << x << "," << y << ")n";} Point operator +(Point &p){ return Point(x + p.x,y + p.y); } Point operator-(){ return Point(-x, -y);} }; int main() { Point p1(2,3); Point p3 = -p1; p3.afficher(); } opérateur binaire + opérateur unaire - Point-9.cpp
  114. 114. Surcharge des opérateurs • Surcharge au niveau de la classe – définition dans la classe – l'objet de classe qui invoque est le membre de gauche – l'appel est équivalent à p1.operator+(p2); antislashn.org C vers C++ 114 class Point{ int x,y; public: Point(int x, int y) {this->x = x; this->y = y; } void afficher(){ cout << "Point en (" << x << "," << y << ")n";} Point operator +(Point &p) { return Point(x + p.x,y + p.y); } };
  115. 115. Surcharge des opérateurs • Surcharge des opérateurs ++ et -- – la définition des opérateurs préfixés est standard – la définition des opérateurs suffixés s'effectue en ajoutant un int comme paramètre supplémentaire à la signaturela signature antislashn.org C vers C++ 115 class Point{ int x,y; public: Point(int x, int y) {this->x = x; this->y = y; } void afficher(){ cout << "Point en (" << x << "," << y << ")n";} Point &operator++() { ++x;++y; return *this;} Point &operator++(int) { x++;y++; return *this;} }; Point-9.cpp ATTENTION : code non fonctionnel
  116. 116. Surcharge des opérateurs • Surcharge de l'opérateur d'affectation = – par défaut fait une copie de surface de la classe class Tableau{ int *tab; int taille; public: … Tableau &operator=(const Tableau &t){ if(this != &t) { t correspondra à t1 antislashn.org C vers C++ 116 { delete [] tab; taille = t.taille; tab = new int[taille]; for(int i=0 ; i<taille ; i++) tab[i] = t.tab[i]; } return *this; } … }; int main() { Tableau t1(5); Tableau t2; for(int i=0 ; i<5 ; i++) t1.set(i,i); t2 = t1; … } appel de operator= Attention : Tableau t2 = t1; aurait appelé le constructeur de copie t2 est l'objet sur qui est invoqué operator=() operateur-affectation.cpp
  117. 117. Surcharge des opérateurs • Surcharge de l'opérateur d'indexation [] – ne peut qu'être qu'un membre de classe – considéré comme un opérateur binaire • x[y] est interprété comme x.operator[](y) – dans une expression telle que– dans une expression telle que • x[i] = y[i] + 1; • il faut que l'affectation se fasse sur x[i], il faut donc que operator[] renvoie une lvalue, ce qui est fait en renvoyant une référence – sinon erreur à la compilation (pas une lvalue) antislashn.org C vers C++ 117
  118. 118. Surcharge des opérateurs • Exemple de surcharge de l'opérateur [] (extrait) class Tableau{ int *tab; int taille; public: ... int &operator[](int i) {return tab[i];} antislashn.org C vers C++ 118 {return tab[i];} ... }; int main() { Tableau t1(5); Tableau t2; Tableau t3(1); ... t3[0] = t1[1] + t2[3]; ... } renvoie une référence vers tab[i] affectation possible car une référence est renvoyée operateur-crochets.cpp
  119. 119. Surcharge des opérateurs • Surcharge de l'opérateur d'appel de fonction () – nommé aussi foncteur ou objet fonction – uniquement en tant que fonction d'une classe – opération binaire est interprété comme• c(x,y) est interprété comme c.operator()(x,y) • prototype de la forme type operator() (paramètres); – ne pas confondre avec l'opérateur de conversion • rappel plus loin antislashn.org C vers C++ 119
  120. 120. Surcharge des opérateurs • Exemple de foncteurs class Inferieur{ public: bool operator()(int i, int j) { return i < j; } bool operator()(char a, char b) { return a < b; } bool operator()(char *s1, char *s2) {return strcmp(s1,s2) < 0; } }; antislashn.org C vers C++ 120 int main() { Inferieur inf; cout << inf(1,2) << endl; cout << inf('z','a') << endl; cout << inf("aa","bb") << endl; system("PAUSE"); } foncteur.cpp
  121. 121. Surcharge des opérateurs • Opérateur de conversion – rappel • syntaxe : operator type () {…} – le type retourné doit correspondre au type redéfini • il sera implicitement appelé chaque fois qu'une conversion sera nécessaire antislashn.org C vers C++ 121 class Point{ int x,y; public: Point(int x, int y) {this->x = x; this->y = y; } operator int() {return x+y;} }; int main() { Point p = Point(2,3); cout << p*2 << endl; system("PAUSE"); } définition de la conversion vers int invocation de la conversion vers int
  122. 122. Surcharge des opérateurs • Les surcharges utilisables et leurs syntaxes sont résumés sur le site Wikipedia – http://en.wikipedia.org/wiki/Operators_in_C_and_C++ antislashn.org C vers C++ 122
  123. 123. C++11 – Rvalue Reference • Une lvalue est une expression possédant un nom et qui reste en mémoire un certain temps – une variable est une lvalue • Une rvalue n'a pas de nom et ne persiste pas – un entier littéral n'a pas de nom et sa portée est très– un entier littéral n'a pas de nom et sa portée est très courte – valeur retour de fonction • Les rvalue references prennent en charge la sémantique de déplacement – syntaxe : && antislashn.org C vers C++ 123
  124. 124. C++11 – Rvalue Reference • Introduction d'une sémantique de déplacement (move) – en C++ il n'y a pas de manière générique de déplacer un objet • si une fonction retourne un objet de taille importante, celui- ci est copié dans une zone temporaire avant d'être à • si une fonction retourne un objet de taille importante, celui- ci est copié dans une zone temporaire avant d'être à nouveau copié vers la zone où le résultat de la focntion est affecté – C++11 ajoute les Rvalues Reference • permet d'appeler la fonction "MoveFrom" à la place du constructeur de copie si la copie correspond à un déplacement antislashn.org C vers C++ 124
  125. 125. C++11 – Constructeur de déplacement • Extrait de code class MyContainer{ int nSize; char* pString; public: MyContainer(MyContainer&& s){ moveIt(*this, s); } antislashn.org C vers C++ 125 } protected: static void moveIt(MyContainer& tgt, MyContainer& src){ cout << "Moving " << src.pString << endl; tgt.nSize = src.nSize; tgt.pString = src.pString; src.nSize = 0; src.pString = nullptr; } ... }
  126. 126. C++11 – Opérateur de déplacement • Extrait de code class MyContainer{ int nSize; char* pString; public: MyContainer& operator=(MyContainer&& s){ delete pString; moveIt(*this, s); return *this; antislashn.org C vers C++ 126 return *this; } protected: static void moveIt(MyContainer& tgt, MyContainer& src){ cout << "Moving " << src.pString << endl; tgt.nSize = src.nSize; tgt.pString = src.pString; src.nSize = 0; src.pString = nullptr; } ... }
  127. 127. C++11 - Sémantique de déplacement • Par rapport aux constructeur et opérateur de copie – extrait de code ... public: MyContainer(const MyContainer& s){ copyIt(*this, s); } MyContainer& operator=(MyContainer& s){ antislashn.org C vers C++ 127 MyContainer& operator=(MyContainer& s){ delete pString; copyIt(*this, s); return *this; } protected: static void copyIt(MyContainer& tgt,const MyContainer& src){ cout << "Copying " << src.pString << endl; delete tgt.pString; tgt.nSize = src.nSize; tgt.pString = new char[tgt.nSize]; strncpy(tgt.pString, src.pString, tgt.nSize); } ...
  128. 128. C++11 - Sémantique de déplacement • Fonction utilitaires de la bibliothèque utility – std::move() • retourne une référence à une rvalue – fonction de transtypage • prend pour paramètre une référence à une lvalue ou une• prend pour paramètre une référence à une lvalue ou une rvalue – std::forward() • fait suivre une variable – retourne une lvalue reference si la variable est une lvalue reference – retourne une rvalue reference si la variable est une rvalue reference antislashn.org C vers C++ 128
  129. 129. Les patrons • Si plusieurs fonctions sont définies de la même façon et ne diffèrent que par les types d'arguments, le développeur doit créer l'ensemble des fonctions – en C on peut définir une macro préprocesseur – le C++ fournit un mécanisme de patrons (templates) de fonction • cette méthode s'étend aux classes antislashn.org C vers C++ 129 int max(int a, int b) { return (a>b) ? a : b ; } double max(double a, double b) { return (a>b) ? a : b ; } #define MAX(a,b) ((a)>(b)) ? a : b
  130. 130. Patron de fonction • Les types des arguments ne sont pas fixés et sont considérés eux-mêmes comme des paramètres – syntaxe • template<typename parametre[,…]> définition_fonction – la fonction max devient– la fonction max devient – le compilateur va générer le code des fonctions en tenant compte des appels • si une fonction du même nom avec les bons types de paramètre existe déjà, le compilateur l'utilisera – class peut être utilisé au lieu de typename antislashn.org C vers C++ 130 template <typename T> T max(T &a,T &b) { return (a>b) ? a : b ; }
  131. 131. Patron de classe • Il peut arriver que plusieurs classes soient définies de manières identiques, aux types près – un patron de classe peut alors être utilisé – syntaxe : • template <typename parametre[,…]> class nom_class{…}• template <typename parametre[,…]> class nom_class{…} antislashn.org C vers C++ 131 template <typename T> class Tableau{ T tab[2]; public: Tableau(T x,T y) {tab[0]=x;tab[1]=y;} void afficher(){ cout << tab[0] << "t" << tab[1] << endl;} }; int main() { Tableau<int> t1(1,2); Tableau<char> t2('a','z'); t1.afficher(); t2.afficher(); } génération des classes en précisant le type template-classe.cpp
  132. 132. Patron de classe • Le compilateur générera les classes nécessaires • Un patron de classe est entièrement codé dans le fichier .h – on ne peut pas pré-compiler un template – pas de fichier .cpp– pas de fichier .cpp • Si les déclarations et définitions sont séparées le nom de la méthode doit être complètement qualifié – dans le même fichier .h (pas de .cpp) – les méthodes ne sont pas inline antislashn.org C vers C++ 132
  133. 133. Patron de classe • Déclarations et définitions séparées template <typename T> class Tableau{ T tab[2]; public: Tableau(T x,T y) {tab[0]=x;tab[1]=y;} void afficher(); }; antislashn.org C vers C++ 133 }; template<typename T> void Tableau<T>::afficher() { cout << tab[0] << "t" << tab[1] << endl;}
  134. 134. Patron de classe • Il est possible de préciser un paramètre template par défaut template <typename T, typename Y=int> class Toto{ T t; Y y; }; type par défaut antislashn.org C vers C++ 134 }; int main(){ Toto<int> t1; Toto<double,double> t2; } équivalent à Toto<int,int>
  135. 135. typename • typename est utilisé pour introduire un type générique – class peut aussi être utilisé • typename sert aussi à introduire les identificateurs de types inconnus dans les templatesde types inconnus dans les templates antislashn.org C vers C++ 135 class A { public: typedef int Y; }; template <class T> class X { typename T::Y i; }; int main(){ X<A> x; }; type définit dans la classe A la classe X suppose que le type générique T définit un type Y typename.cpp
  136. 136. Membres statiques • Donnée statique – la classe contient la déclaration de la donnée statique – la définition de la donnée statique s'effectue au niveau global class Point{ int x,y; public: déclaration membres-static.cpp antislashn.org C vers C++ 136 public: static int nombre; Point(int x, int y) { this->x = x ; this->y = y; nombre++;} Point(){x=y=0; nombre++;} ~Point() {nombre--;} void afficher(){cout << "Point " << nombre << " en (" << x << "," << y << ")n";} }; int Point::nombre=0; int main() { Point p1; Point p2(5,6); p1.afficher(); p2.afficher(); system("PAUSE"); } définition et initialisation
  137. 137. Membres statiques • Fonction statique – n'a pas accès aux membres non statiques – le pointeur this n'est pas passé à la fonction statique class Point{ int x,y; static int nombre; déclaration (privée) antislashn.org C vers C++ 137 static int nombre; public: Point(int x, int y) { this->x = x ; this->y = y; nombre++;} Point(){x=y=0; nombre++;} ~Point() {nombre--;} static int getNombre() {return nombre;} void afficher(){ cout << "Point " << nombre << " en (" << x << "," << y << ")n";} }; int Point::nombre=0; int main() { Point p1; Point p2(5,6); cout << Point::getNombre() << endl; system("PAUSE"); } fonction d'accès statique appel de la fonction statique membres-static.cpp
  138. 138. Héritage • Syntaxe de base class classe_derivee : type_protection classe_base {…}; – le type de protection définit l'accessibilité dans la classe dérivée des membres de la classe de base • on ne peut que restreindre l'accessibilité• on ne peut que restreindre l'accessibilité • dans tous les cas les membres privés de la classe de base ne sont pas accessibles dans la classe dérivée – public : on conserve les accessibilités – protected : les membres publiques et protégés de la classe de base deviennent protégés dans la classe dérivée – private : les membres publiques et protégés de la classe de base deviennent privés dans la classe dérivée antislashn.org C vers C++ 138
  139. 139. Héritage • La classe dérivée hérite de l'ensemble des membres de la classe de base – les membres privés sont hérités mais ne sont pas accessible par la classe dérivée • principe d'encapsulation, il faut fournir des méthodes• principe d'encapsulation, il faut fournir des méthodes publiques pour accéder aux propriétés privées – il y réunion des membres • chaque objet de la classe dérivée contient un objet de la classe de base antislashn.org C vers C++ 139
  140. 140. Héritage • Empreinte mémoire – la classe B dérive de la classe A class A{ char ta[256]; }; class B : public A{ heritage-1.cpp antislashn.org C vers C++ (version v1.1) 140 class B : public A{ char tb[256]; }; int main() { cout << "Encombrement de A : " << sizeof(A) << endl; cout << "Encombrement de B : " << sizeof(B) << endl; } char ta[256] char ta[256] char tb[256]instance de A instance de B sous instance A
  141. 141. Héritage • Exemple class Vehicule{ char *marque; public: Vehicule(){marque = "INCONNU"; } Vehicule(char * marque){this->marque = marque;} void afficher() {cout << "Vehicule - marque : "<<marque<<endl;} }; Vehicule-1.cpp antislashn.org C vers C++ 141 }; class Voiture : public Vehicule{ }; int main() { Voiture v1; v1.afficher(); system("PAUSE"); } Voiture spécialise Véhicule utilisation de la méthode de la classe de base
  142. 142. Héritage – sous-typage • Conversion de classe dérivée en classe de base – la conversion est implicite dès que cela est nécessaire – la visibilité est alors réduite à la classe de base class Voiture : public Vehicule{ public: Vehicule-1.cpp antislashn.org C vers C++ 142 public: void rouler(){cout << "La voiture " << getMarque() << " roulen";} }; int main() { Voiture v1; v1.afficher(); v1.rouler(); Vehicule v2 = v1; v2.rouler(); system("PAUSE"); } accesseur défini dans Vehicule pour la propriété privée de Vehicule OK : v1 est de type Voiture ERREUR : v2 est de type Vehicule
  143. 143. Héritage – forçage vers la classe dérivée • Il est illicite de convertir un type de base vers un type dérivé. • Un pointeur sur la classe de base peut être converti en un pointeur vers la classe dérivée – conversion explicite – n'a de sens que si l'objet concret pointé par le pointeur est bien du type de la classe dérivée antislashn.org C vers C++ 143
  144. 144. Héritage – forçage vers la classe dérivée • Exemple class Vehicule{ char *marque; public: Vehicule(){marque = "INCONNU"; } Vehicule(char * marque){this->marque = marque;} void afficher() {cout << "Vehicule - marque : "<<marque<<endl;} char * getMarque(){ return marque;} }; Vehicule-1.cpp antislashn.org C vers C++ 144 class Voiture : public Vehicule{ public: void rouler(){cout << "La voiture " << getMarque() << " roulen";} }; int main() { Voiture *vo1 = new Voiture(); Vehicule *ve1 = vo1; Voiture *vo2; vo2 = (Voiture *) ve1; vo2->rouler(); system("PAUSE"); } OK car ve1 pointe vers un objet concret Voiture sous-typage ve1 de type Vehicule pointe vers un objet concret de type Voiture
  145. 145. Héritage • L'accès à un membre peut être désignés par son nom ou par son nom complètement qualifié. – si le nom du membre de classe à la même nom dans la classe de base et la classe dérivée, la référence au membre de la classe de base passe par le nom qualifié class A{ public: heritage-2.cpp antislashn.org C vers C++ 145 public: void f() { cout << "A::f()n";} }; class B : public A{ public: void f() { cout << "B::f()n";} }; int main() { A a; B b; a.f(); b.f(); b.A::f(); system("PAUSE"); } accès à la fonction de la classe de base
  146. 146. Héritage – les constructeurs • Chaque fois qu'un constructeur d'une classe dérivée est appelé, le constructeur de la classe de base est d'abord appelé – deux cas sont à considérés • le cas général• le cas général • le cas du constructeur de copie antislashn.org C vers C++ 146
  147. 147. Héritage – les constructeurs • Cas général – si un constructeur de la classe dérivée est appelé (autre que le constructeur de copie) • le constructeur de la classe de base appelé est celui qui est présent dans la liste d'initialisationprésent dans la liste d'initialisation • s'il n'y a pas de liste d'initialisation, le constructeur par défaut de la classe de base est appelé • si aucun constructeur n'est défini dans la classe dérivée, le constructeur par défaut de la classe de base est appelé antislashn.org C vers C++ 147
  148. 148. Héritage – les constructeurs • Exemple : cas général class A{ public: A(){ cout << "A()n";} A(int i){ cout << "A(int i)n";} }; class B : public A{ public: heritage-3.cpp antislashn.org C vers C++ 148 public: B(){ cout << "B()n";} B(int i):A(i){ cout << "B(int i)n";} B(char c){ cout << "B(char c)n";} }; int main() { B b; cout << endl; B c(1); cout << endl; B d('a'); cout << endl; system("PAUSE"); }
  149. 149. Héritage – les constructeurs • Cas du constructeur de copie – lorsqu'une classe ne possède pas de constructeur par copie le compilateur en fournit un – si la classe dérivée n'a pas de constructeur de copie, le constructeur de copie (défini ou par défaut) de laconstructeur de copie (défini ou par défaut) de la classe mère est appelé – si la classe fille possède un constructeur de copie, le constructeur de la classe mère appelé dépend de la liste d'initialisation • si la liste est absente ou n'indique pas de constructeur pour la classe mère, c'est le constructeur par défaut de la classe mère qui est appelé antislashn.org C vers C++ 149
  150. 150. Héritage – les constructeurs • Exemple : constructeur de copie class A{ public: A(){ cout << "A()n";} A(const A &a){ cout << "A(const A &a)n";} }; class B : public A{ public: B(){ cout << "B()n";} appel du constructeur par défaut de A heritage-4.cpp antislashn.org C vers C++ 150 B(){ cout << "B()n";} B(const B &b){ cout << "B(const B &b)n";} }; class C : public A{ public: C(){ cout << "C()n";} C(const C &c):A(c){ cout << "C(const C &c)n";} }; int main() { B b1; B b2 = b1; C c1; C c2 = c1; } appel du constructeur de copie de A
  151. 151. Héritage - template • Un template peut hériter d'un autre template • Une classe peut hériter d'un template template <typename T> class X{ T t; }; heritage_template.cpp antislashn.org C vers C++ 151 }; template <typename U, typename V> class Y : public X<U>{ V u; }; class V : public X<float>{ }; int main(){ Y<int,double> y; V v; }
  152. 152. Dérivation et opérateur d'affectation • Similaire au constructeur de copie – soit b2 = b1; où b1 et b2 sont des instances d'une classe B dérivée de A – si l'opérateur d'affectation de B n'a pas été redéfini, l'opérateur d'affectation de A est appelél'opérateur d'affectation de A est appelé – si l'opérateur d'affectation de B a été redéfini, l'opérateur d'affectation de A n'est pas appelé • toutes les affectations de la partie de la classe B dépendant de A doivent être codée explicitement antislashn.org C vers C++ 152
  153. 153. Dérivation et opérateur d'affectation class A{ public: A(){cout << "++ CONSTRUCTEUR A()" << endl;} A(const A &a){cout << "++ CONSTRUCTEUR COPIE A(const A &a)" << endl;} A &operator=(const A &a) { cout << "=> OPERATOR=(const A &a) de A" << endl; return *this;} }; class B : public A{ public: B(){cout << "++ CONSTRUCTEUR B()" << endl;} B(const B &b){cout << "++ CONSTRUCTEUR COPIE B(const B &b)" << endl;} heritage-5.cpp antislashn.org C vers C++ 153 B &operator=(const B &b) { A *pa1 = this; A *pa2 = const_cast<B*> (&b); *pa1 = *pa2; cout << "=> OPERATOR=(const B &b) de B" << endl; return *this;} }; int main() { B b1; cout << "============================" << endl; B b2; cout << "============================" << endl; b1 = b2; cout << "============================" << endl; } affectation de la partie A de l'instance
  154. 154. Polymorphisme • Un des principes du polymorphisme est qu'une classe dérivée est compatible avec sa classe de base. – là où une Figure est prévue on doit pouvoir y substituer un Carre • tous les services offerts par une Figure sont offert par un Carre – sous réserve des droits d'accès • la conversion d'une classe vers sont type de base est une conversion standard Carre c; Figure f = c; antislashn.org C vers C++ 154 class Figure{ public: void afficher(){ cout << "A CODER" << endl; } }; class Carre : public Figure{ public: void afficher(){ cout << "AFFICHAGE D'UN CARRE" << endl; } }; Figure-1.cpp
  155. 155. Polymorphisme • Selon que l'on applique cette conversion sur des objets ou des pointeurs la conversion est effectuée différemment • Convertir un objet Carre vers un objet Figure revient à lui enlever les membres qui ne font pas partie de Carre – il y a perte effective d'information – peut être vu comme l'appel implicite d'une méthode de– peut être vu comme l'appel implicite d'une méthode de conversion de Carre vers Figure antislashn.org C vers C++ 155 Carre c; Figure f = c; Figure Carre Figure instance c static_cast<Figure> (c)
  156. 156. Polymorphisme • Convertir un pointeur vers Carre vers un pointeur vers Figure ne fait perdre aucune information – l'instance n'offre que les services de Figure, mais il ne cesse pas d'être un Carre avec tous ces membres antislashn.org C vers C++ 156 Carre c; Figure *pf = &c; Figure Carre pf static_cast<Figure *> (&c)
  157. 157. Polymorphisme • Exemple – seul l'appel de l'affichage d'un Carre par un objet de type Carre fonctionne !!! – il faut distinguer le type statique et le type dynamique antislashn.org C vers C++ 157 int main() { Carre c; Figure f1; Figure f2 = c; Figure *f3 = &c; Figure &rf = c; c.afficher(); f1.afficher(); f2.afficher(); f3->afficher(); rf.afficher(); } Figure-1.cpp
  158. 158. Polymorphisme • Par défaut la détermination du membre accédé à travers un pointeur ou une référence est fait durant la compilation – donc par le type statique du pointeur ou de la référence – le type statique d'une expression est connu à la compilation – le type dynamique est déterminé par la valeur courante de l'expression • peut évoluer durant l'exécution• peut évoluer durant l'exécution • Par défaut la détermination du membre à accéder à travers un pointeur ou une référence se fait durant la compilation – c'est-à-dire d'après le type statique du pointeur ou de la référence • Pour que la détermination soit effectuée dynamiquement il faut déclarer les fonctions virtuelles – quand déclarer une fonction virtuelle ? • si une fonction est redéfinie dans les classes dérivées • si une fonction est appelée à travers des pointeurs ou références antislashn.org C vers C++ 158
  159. 159. Fonctions virtuelles • Types statiques et dynamiques class B {}; class D : public B {}; int main() { D d; B b = d; B *pb = &d; – le type statique de *pb et de rb est B • analyse du programme, déterminé à la compilation – le type dynamique de *pb et de rb est D antislashn.org C vers C++ 159 B *pb = &d; B &rb = d; }
  160. 160. Fonctions virtuelles class Figure{ public: virtual void afficher(){ cout << "A CODER" << endl; } }; class Carre : public Figure{ public: void afficher(){ cout << "AFFICHAGE D'UN CARRE" << endl; } fonction virtuelleFigure-2.cpp antislashn.org C vers C++ 160 } }; int main() { Carre c; Figure f1; Figure f2 = c; Figure *f3 = &c; Figure &rf = c; c.afficher(); f1.afficher(); f2.afficher(); f3->afficher(); rf.afficher(); } f1 et f2 sont des instances de Figure Perte des informations propre à Carre
  161. 161. Fonctions virtuelles • La création d'une classe polymorphe implique l'initialisation d'un pointeur vptr vers une vtable de la classe • Un appel comme f3->afficher() – en absence de fonction virtuelle aurait été traduit par Figure::afficher(f3) – avec une fonction virtuelle il est traduit comme (*f3->vptrFigure[0])(f3)(*f3->vptrFigure[0])(f3) • [0] car affiche() est la première fonction virtuelle antislashn.org C vers C++ 161 propriétés de Figure vprtFigure instance de Figure &A::affiche vtable de Figure autres méthodes virtuelles
  162. 162. Fonctions virtuelles • Un objet n'est pas typé tant qu'il n'est pas complètement construit – un constructeur ne peut pas être virtuel – l'appel d'une fonction virtuelle dans un constructeur n'a pas toujours l'effet escomptén'a pas toujours l'effet escompté • Le destructeur peut-être virtuel – ATTENTION : si le destructeur n'est pas virtuel le destructeur de la classe fille ne sera pas appelé antislashn.org C vers C++ 162
  163. 163. Destructeur virtuel class A{ public: A(){ cout << "++ CONSTRUCTEUR A()" << endl;} ~A(){ cout << "-- DESTRUCTEUR ~A()" << endl;} }; class B:public A{ public: B(){ cout << "++ CONSTRUCTEUR B()" << endl;} ~B(){ cout << "-- DESTRUCTEUR ~B()" << endl;} }; destructeur-virtuel.cpp Destructeur non virtuel antislashn.org C vers C++ 163 }; int main(){ A *pa = new B(); delete pa; } Pas d'appel au destructeur de B
  164. 164. Classe abstraite • Des fonctions peuvent être purement virtuelles – pas d'implémentation fournie – présente le vocabulaire de base – syntaxe : virtual void nom_fonction() = 0; • Une classe qui comporte au moins une fonction virtuelle pure est une classe abstraite – pas de création d'instance – une classe abstraite pure ne comporte que des fonctions virtuelles pures antislashn.org C vers C++ 164
  165. 165. Classe abstraite • Exemple class Figure{ public: virtual void afficher() =0 ; }; class Point : public Figure{ int x,y; public : Point(int x, int y){this->x = x, this->y = y;} void afficher() { cout << "Point en (" << x << "," << y << ")n"; } }; class Carre : public Figure{ classe abstraite Figure-3.cpp antislashn.org C vers C++ 165 class Carre : public Figure{ Point xy; int cote; public: Carre(int x, int y, int cote):xy(x,y) {this->cote = cote;} void afficher() { cout <<"Carre cote : " << cote << endl; } }; int main() { Carre *c = new Carre(1,2,3); Point *p = new Point(8,9); c->afficher(); p->afficher(); }
  166. 166. Héritage multiple • En C++ une classe peut hériter de plusieurs classes de base – lors de l'initialisation de la classe B, l'ordre d'appel des constructeurs correspond à l'ordre de déclaration des classes de baseclasses de base antislashn.org C vers C++ 166 class A1{ }; class A2{ }; class B : public A1, public A2{ };
  167. 167. Héritage multiple • Si les classes A1 et A2 sont elles même dérivées d'une même classe de base, des ambigüités peuvent apparaitre – les classes virtuelles permettent de solutionner ces ambigüitésambigüités • Forçage de type • les valeurs de pa1 et pa2 sont différentes antislashn.org C vers C++ 167 B *pb = new B; A1 *pa1 = pb; A2 *pa2 = pb;
  168. 168. Héritage multiple • Les membres d'une classe possèdent une portée – par dérivation de classe ou imbrication d'une classe dans une autre – à chaque niveau de dérivation est associée une portée, et un nom défini à ce niveau masque le même nom défini à un niveau supérieurun niveau supérieur – ainsi avec l'héritage multiple il peut arriver qu'un même nom de fonction soit utilisé dans deux classes de base • erreur de compilation lors de l'appel de la fonction • le développeur peut préciser la classe de base utilisée • certains compilateur permettent de mettre en place une clause using afin de changer la portée des fonctions – il faut que les fonctions héritées aient des signatures différentes antislashn.org C vers C++ 168
  169. 169. Héritage multiple • Exemple class A1{ int i; public: void f(int i) { cout << "A1::f(int)n"; } }; class A2{ int j; heritage-multiple-1.cpp antislashn.org C vers C++ 169 int j; public: void f(char c) { cout << "A2::f(char)n"; } }; class B : public A1, public A2{ using A1::f; using A2::f; }; int main() { B b; b.f(1); } clauses 'using' pour changer la portée des fonctions appel de la fonction sans avoir besoin de préciser la classe de base : b.A1::f(1);
  170. 170. Héritage multiple • Empreinte mémoire class A1{ char ta1[100]; }; class A2{ char ta2[100]; }; class B : public A1, public A2{ char tb[100]; heritage-multiple-2.cpp antislashn.org C vers C++ 170 char ta1[100] char ta2[100] instance de B sous instance A1 char tb[100]; }; int main() { cout << "Encombrement pour A1 : " << sizeof(A1) << endl; cout << "Encombrement pour A2 : " << sizeof(A2) << endl; cout << "Encombrement pour B : " << sizeof(B) << endl; } char tb[100] sous instance A2
  171. 171. Héritage multiple • Soit le schémas d'héritage class A {...}; class B1 : public A {...}; class B2 : public A {...}; class C: public B1, public B2 {...}; b1 aa b2 c – une instance de C comprend alors deux objets A • occupation inutile de mémoire • complication du codage – la déclaration virtuelle de A dans la définition de B1 et B2 résout le problème • il n'y aura qu'un objet a antislashn.org C vers C++ 171
  172. 172. Héritage multiple • Sans déclaration virtual class A{ char a[100]; }; class B1:public A{ char b1[100]; }; char a[100] instance de A char a[100] char a[100] heritage-multiple-3.cpp antislashn.org C vers C++ 172 class B2:public A{ char b2[100]; }; class C:public B1,public B2{ char c[100]; }; char b1[100] instance de B1 char b2[100] instance de B2 char b1[100] char a[100] char b2[100] instance de C char c[100] char a[100] sous instance A de B1 sous instance A de B2 sous instance B1 sous instance B2
  173. 173. Héritage multiple • Le code devient alors class A {...}; class B1 : virtual public A {...}; class B2 : virtual public A {...}; class D: public B1, public B2 {...}; b1 a b2 d – le mécanisme d'appel des constructeurs est alors modifié • le compilateur ignore les appels aux constructeurs de A qui figureraient dans une liste d'initialisation de B1 et B2 • on peut appeler les constructeurs de A dans une liste d'initialisation de D antislashn.org C vers C++ 173
  174. 174. Héritage multiple • Avec déclaration virtual class A{ char a[100]; }; class B1:virtual public A{ char b1[100]; }; char a[100] instance de A char b2[100] 4 octets char b1[100] 4 octets antislashn.org C vers C++ 174 class B2:virtual public A{ char b2[100]; }; class C:public B1,public B2{ char c[100]; }; instance de C sous instance A sous instance B1 sous instance B2 heritage-multiple-3.cpp instance de B2 char a[100] instance de B1 char a[100] char b1[100] char a[100] 4 octets char b2[100] 4 octets char c[100]
  175. 175. Classe – forme générale • Forme générale – un constructeur par défaut • allocation de certaines parties de l'objet – un destructeur • désallocation des parties allouées dans le constructeur• désallocation des parties allouées dans le constructeur – constructeur de copie – opérateur d'affectation antislashn.org C vers C++ 175 class T{ public: T(…); T(const T&); ~T(); T& operator= (const T&); };
  176. 176. Classe – forme générale • Héritage et forme générale – classe de base T respectant la forme générale • destructeur virtuel • méthodes devant être redéfinies par les classes dérivées virtuelles – classe dérivée U respectant la forme générale antislashn.org C vers C++ 176 class U :public T{ public: U(…); U(const U &x):T(x){ // recopie de la partie spécifique à U } ~U(); U & operator=(const U & x){ T *ad1 = this; T *ad2 = &x; *ad1 = ad2; // affectation de la partie héritée T // affectation de la partie non héritée } };
  177. 177. Identification dynamique du type • Le coût du polymorphisme est une indirection supplémentaire pour chaque appel de méthode – chaque objet à un encombrement supplémentaire égal à la taille d'un pointeur, quelque soit le nombre de fonctions virtuellesde fonctions virtuelles • Si un pointeur pointe sur un objet – on connait le type réellement pointé • tout du moins le développeur le connait – on connait le type du pointeur défini à la compilation – il peut être souhaitable de voir l'objet pointé comme l'objet concret, et non pas comme l'objet de base antislashn.org C vers C++ 177
  178. 178. Identification dynamique de classe • Opérateur dynamic_cast – syntaxe : dynamic_cast<type>(expression) – permet la conversion d'une expression de type pointeur vers une autre • si une classe de base A est dérivée en BA • si une classe de base A est dérivée en B – la conversion B* vers A* ne fait rien de plus que la conversion standard – la conversion A* vers B* n'a de sens que si le type concret pointé est bien de type B* – l'opérateur dynamic_cast rend la conversion sure et portable » rend l'adresse de l'objet si la conversion est possible » renvoie NULL si la conversion n'est pas possible antislashn.org C vers C++ 178 A B
  179. 179. Identification dynamique de classe • Exemple sur dynamic_cast class A{ virtual void foo(){} }; class B1:public A{}; class B2:public A{}; class B3{}; class C:public B1, public B2, protected B3{}; dynamic_cast.cpp antislashn.org C vers C++ 179 class C:public B1, public B2, protected B3{}; int main(void) { A *pa = new A; B1 *pb1 = new C; C *pc = new C; A &ra = *pa; // Vaut null cout << "dynamic_cast<C *>(pa) : " << dynamic_cast<C *>(pa) << endl; // C dérive de B3 protected //cout << "dynamic_cast<B3 *>(pc) : " << dynamic_cast<B3 *>(pc) << endl; // Ambiguité : quel A ? //cout << "dynamic_cast<A *>(pc) : " << dynamic_cast<A *>(pc) << endl; cout << "dynamic_cast<C *>(pb1) : " << dynamic_cast<C *>(pb1) << endl; cout << "dynamic_cast<A *>(pb1) : " << dynamic_cast<A *>(pb1) << endl; cout << "dynamic_cast<B2 *>(pb1) : " << dynamic_cast<B2 *>(pb1) << endl; } ne passe pas à la compilation
  180. 180. Identification dynamique de classe • Opérateur typeid – permet de connaitre le véritable type d'un objet désigné par un pointeur ou une référence – renvoie un objet de type type_info • contient entre autre – une méthode name() – les opérateur == et != pour la comparaison antislashn.org C vers C++ 180 int main(void) { D d; B &b = d; NV &nv = d; int i; B b1; cout << typeid(b).name() << endl; cout << typeid(3.2).name() << endl; cout << typeid(nv).name() << endl; cout << typeid(d).name() << endl; cout << typeid(b1).name() << endl; if(typeid(b)==typeid(d)) cout << "type identique" << endl; } typeid.cpp
  181. 181. Pointeur sur membre de classe • Il est courant de manipuler des fonctions au travers de pointeurs – mécanisme du C – transposé sur les classes en C++, cela revient à référencer une fonction statique d'une classeréférencer une fonction statique d'une classe antislashn.org C vers C++ 181 class A{ public: static int doubler(int i) {return i*2;} }; int main() { A a; int (*pf)(int); pf = A::doubler; cout << (*pf)(5) << endl; system("PAUSE"); } pointeur vers fonction pointeur-membre-1.cpp
  182. 182. Pointeur sur membre de classe • Pour un objet donné, il est toujours possible de référencer par pointeur une donnée – sous réserve de l'accessibilité class A{ public: antislashn.org C vers C++ 182 public: int i; int doubler(int i) {return i*2;} }; int main() { A a; int *pi = &a.i; } pointeur vers int
  183. 183. Pointeur sur membre de classe • Mais il peut être utile de pouvoir manipuler des notions plus abstraites – pointer sur une fonction membre non statique – pointer sur une fonction de la classe ayant un argument de type int et retournant un doubleargument de type int et retournant un double – pointer sur un champ de type int de la classe • C++ met en place un syntaxe particulière pour ces notions – syntaxe pouvant paraitre insolite – le pointeur n'a pas son sens usuel : sa valeur n'est pas accessible antislashn.org C vers C++ 183
  184. 184. Pointeur sur membre de classe • Pointeur sur une donnée membre – déclaration • type classe::*pointeur; – initialisation • pointeur = &classe::donnee;• pointeur = &classe::donnee; • Après l'initialisation le pointeur ne désigne pas d'adresse en mémoire – il est associé à l'offset du champ dans l'objet – il peut être utilisé ensuite sur un objet de la classe • objet.*pointeur; antislashn.org C vers C++ 184
  185. 185. Pointeur sur membre de classe • Exemple de pointeur sur une donnée membre using namespace std; class A{ public: int i; A(int j){i=j;} pointeur-membre-2.cpp antislashn.org C vers C++ 185 int doubler(int i) {return i*2;} }; int main() { A a(20); int A::*pi = &A::i; cout << a.*pi << endl; system("PAUSE"); } déclaration et initialisation du pointeur utilisation du pointeur
  186. 186. Pointeur sur membre de classe • Pointeur sur une fonction membre – déclaration • type_retour (class::*pointeur)(liste_type_arguments); – initialisation • pointeur = &classe::fonction; • Comme le cas précédent le pointeur ne contient• Comme le cas précédent le pointeur ne contient pas l'adresse – il ne peut être converti vers un pointeur vers fonction au sens C – il peut être utilisé par une instance de la classe • (objet.*pointeur)(liste_paramètres); antislashn.org C vers C++ 186
  187. 187. Pointeur sur membre de classe • Exemple de pointeur sur une fonction membre class A{ public: int i; A(int j){i=j;} int doubler(int i) {return i*2;} }; pointeur-membre-3.cpp antislashn.org C vers C++ 187 int main() { A a(20); A *pa = &a; int (A::*pf)(int) = &A::doubler; cout << (a.*pf)(56) << endl; cout << (pa->*pf)(56) << endl; system("PAUSE"); } déclaration et initialisation du pointeur sur fonction membre utilisation du pointeur via l'instance utilisation du pointeur via un pointeur vers l'instance

×