Introduction au langage C++
Introduction au langage C++
SMA
Langage C++
Hassan Silkan
Les commentaires
Sur plusieurs lignes: /* .............comme en C...................*/
Sur une seule ligne: //.... spécifique C++......
Langage C++
Les E/S
Entrées/sorties fournies à travers la librairie < iostream>
cout << expr1 << … << exprn
Instruction affichant expr1 puis expr2, etc.
cout : « flot de sortie » associé à la sortie standard (stdout)
<< : opérateur binaire associatif à gauche, de première opérande cout et de
2ème l’expression à afficher, et de résultat le flot de sortie
<< est l’opérateur surchargé (ou sur-défini)⇒ utilisé aussi bien pour les
chaînes de caractères, que les entiers, les réels etc.
cin >> var1 >> … >> varn
Instruction affectant aux variables var1, var2, etc. les valeurs lues au clavier.
cin : « flot d’entrée » associée à l’entrée standard (stdin)
>> : opérateur similaire à <<
Langage C++
Les types de base
Le type d’une donnée détermine :
La place mémoire (sizeof())
Les opérations légales
Les bornes
Déclaration et initialisation de variables :
bool var_bool = true; // variable boléenne nouveu type en C++
int i = 0; // entier
long j = 123456789; // entier long
float f = 3.1; // réel
double pi = 3.141592653589793238462643; // réel à double précision
char c=‘a’; // caractère
« Initialisation à la mode objet » :
int i(0) ;
Long l (123456789);
Langage C++
Les constantes
Le qualificatif const peut être utilisé pour une expression constante:
const type_var var=cte;
Une expression déclarée avec const a une portée limitée au fichier source qui la
contient.
Exemple:
const int N=5; // par convention une constante est écrite en majuscule
int t[N]; // en C il fallait #define N 5
Langage C++
Les références
une référence sur une variable est un identificateur qui joue le rôle d'un alias
(pseudo) de cette variable.
Syntaxe: type &nom_ref = var;
exemple:
int n;
int &rn=n; // rn est une référence de n
n=10;
cout<< rn; //affiche 10
une référence ne peut être vide, elle doit toujours être initialisée lors de sa
déclaration, i.e : int &rn ; // erreur!
Il est possible de référencer des valeurs numériques, dans ce cas il faut les
déclarer comme constantes, i.e: int &rn=3; // erreur!
const int &rn=3; // OK
Les références et les pointeurs sont liés.
Langage C++
Déclaration des fonctions
L'utilisation d'une fonction sans aucune déclaration ou définition au préalable est
une erreur à la compilation.
Le prototype doit figurer dans tout fichier source qui utilise cette fonction et ne
contenant pas sa définition.
Une fonction en C++ doit spécifier son type de retour, void si elle ne retourne
rien.
fct(int, int); // erreur!
void fct(int, int); //OK
int fct(void); int fct();
Langage C++
Transmission des arguments
En C++ il y a 3 méthodes de passage des variables en paramètres à une fonction:
Passage par valeur: la valeur de la variable en paramètre est copiée dans une
variable temporaire. Les modifications opérées sur les arguments dans la
fonction n'affectent pas la valeur de la variable passée en paramètre.
Passage par adresse: consiste à passer l'adresse d'une variable en paramètre.
Toute modification du paramètre dans la fonction affecte directement la variable
passée en paramètre.
Passage par référence: le passage par adresse présente certains inconvénients,
pour résoudre ces inconvénients, C++ introduit le passage par référence.
En pratique, il est recommandé ( pour des raisons de performances) de passer par
référence tous les paramètres dont la copie peut prendre beaucoup de temps.
Langage C++
Arguments par défaut
C++ offre la possibilité de donner des valeurs par défaut aux paramètres d'une
fonction ( exo TD).
Une fonction peut définir des valeurs par défaut pour tous ses paramètres ou
seulement une partie.
Les valeurs par défaut doivent être mentionnées soit dans le prototype de la
fonction soit dans sa définition.
Les paramètres ayant une valeur par défaut doivent être placés en dernier dans la
liste des arguments.
void fct ( int = 33 , int); //erreur!
Langage C++
Surcharge des fonctions
La surcharge (surdéfinition) des fonctions consiste à donner un même nom à
plusieurs fonctions.
int max(int a, int b); // fonction 1
int max( int a, int b, int c); // fonction 2
int max( int* tab, int taille); // fonction 3
Pour différencier entre deux fonctions qui portent le même nom, le compilateur
regarde le type et le nombre des arguments effectifs: la liste des types des
arguments d'une fonction s'appelle la signature de la fonction.
La surcharge n'est acceptable que si toutes les fonctions ont des signatures
différentes, et n'a un sens que si les surdéfinitions ont un même but.
Il est également possible de surcharger les opérateurs( voir les classes)
Langage C++
Les fonctions inline
Une fonction ''inline'' est une fonction dont les instructions sont incorporées par le
compilateur à chaque appel.
Syntaxe: inline type fonct( arguments...) {… … }
Les fonctions ''inline'' permettent de gagner au niveau temps d'exécution, mais
augmentent la taille des programmes en mémoire.
Contrairement aux macro dans C, les fonctions ''inline'' évitent les effets de bord (
dans une macros l'argument peut être évalué plusieurs fois avant l'exécution de la
macro).
Langage C++
Allocation dynamique
En C++, les fonctions malloc et free sont remplacées avantageusement par les
opérateurs unaire new et delete.
main()
{ int *pi = new int;
int *tab = new int[10];
if ((pi != NULL) && (tab != NULL))
{
...
delete pi;
delete [] tab;
}
}
Classes et Objets
Définition d'une classe
La déclaration d'une classe consiste à décrire ses membres (membres données et
prototypes de ses fonctions membres) groupés en sections. Chaque section est
étiquetée par l'un des mots clés : private, public, ou protected, qui précisent le mode
d'accès aux membres contenus dans la section.
private: accès autorisé seulement par les fonction membres
public: accès libre
protected: accès autorisé seulement dans les fonctions membres de la classe et de
ses dérivées (voir héritage).
Pour déclarer une classe, on utilise le mot clé class.
Classes et Objets
Exemple
class Point
{
private: // membres privés par défaut
int x;
int y; Données membres ( ou attributs) privés
public: // membres publiques
void initialise(int,int);
void deplace(int,int); Méthodes public
void affiche();
} ;
La mention d'accès par défaut dans une classe est private.
La définition d'une classe consiste à définir les prototypes des fonctions membres.
Pour les définir on utilise l'opérateur de portée (::) :
type nom_class::fct(arguments) {……}
Classes et Objets
Au sein de la définition d'une fonction membre, les autres membres (privés ou
publiques) sont directement accessibles (il n'est pas nécessaire de préciser le nom
de la classe):
void point::initialise(int abs, int ord)
{
x = abs;
y = ord;
}
Remarques:
Toutes les possibilités offertes par C++ pour les fonctions restent valables pour les
fonctions membres (surcharge, arguments par défaut, …).
Toute fonction membre définie dans sa classe (dans la déclaration de la classe) est
considérée par le compilateur comme une fonction inline. Le mot clé inline n'est
plus utilisé.
Classes et Objets
Utilisation d'une classe
Un objet (ou instance) nom_objet d'une classe, nommée nom_classe est déclaré
comme une variable de type nom_classe :
nom_classe nom_objet;
#ifndef, #define et #endif sont ajoutés aux fichiers include pour que le fichier
ne soit inclus qu’une seule fois lors d’une compilation.
dans tout programme utilisant la classe nom_classe, on doit inclure le fichier
d'entête ''nom_classe.h''. Un tel programme doit aussi pouvoir accéder au
module objet résultant de la compilation du fichier source contenant la
définition de la classe.
Classes et Objets
Objets transmis en argument
Considérons une classe T et une fonction F dont l'un des paramètres est un
objet de T transmis par valeur, par adresse ou par référence. Soit U une instance de
T transmis en argument à F, alors:
1. Si F est une fonction membre de T, elle aura accès à tous les membres données
de U, sinon elle n'aura accès qu'aux membres publiques de U.
2. Si la transmission de U se fait par valeur, il y a recopie des membres données de
U dans un emplacement locale à F, ce qui entraîne certains problèmes si la classe
contient des pointeurs.
Classes et Objets
Exemple
Définir une fonction qui permet de comparer deux instances de la classe
Point. Cette fonction devra retourner "true" si les deux objets coïncident et "false"
sinon.
La comparaison nécessite l'accès aux coordonnées des points, qui sont des
données privés, par suite, la fonction doit être une fonction membre de la classe.
La déclaration de la fonction dans la classe sera :
bool coincide(Point);
Et sa définition:
bool Point::coincide(Point pt)
{
return ( (pt.x == x) && (pt.y == y));
}
Classes et Objets
Objet fourni en valeur de retour
Etant donné une classe T et une fonction F qui a l'une des formes suivantes :
T F(arguments); // retour par valeur
T * F(arguments); // retourne l'adresse
T & F(arguments); // retourne une référence
Alors F aura accès à tous les membres de l'objet retourné si elle est une fonction
membre de T, si non elle n'aura accès qu'aux membres publics de la classe.
Notez bien que d'une manière générale, une fonction ne doit pas retourner un
pointeur (ou une référence) sur une variable locale, du fait que la zone mémoire
occupée par une variable locale à une fonction est automatiquement considérée
comme libre à la fin de la fonction. Ainsi, par exemple :
int * fct_adr() { int n; … …, return &n}
int & fct_ref() { int n; … …, return n}
fournirons des résultants imprévisibles et erronés.
Classes et Objets
Exemple
On désire définir la fonction symetrique() qui permet de retourner le symétrique
d'un point de la classe Point.
Cette fonction doit être une fonction membre de la classe Point, puisqu'elle doit
accéder aux coordonnées du point, qui sont des données privées. La valeur de retour
sera de type Point La déclaration de la fonction dans la classe sera :
Point symetrique();
et sa définition
Point Point::symetrique()
{ Point pt;
pt.x = -x; pt.y = -y;
return pt;
}
Classes et Objets
Fonctions membres statiques
On distingue deux types de membres :
Membres d'instance : membres associés à une instance de la classe.
Membres de classe : membres associés à la classe et qui ne dépendent d'aucune
instance de la classe.
Les membres de classe sont déclarés avec l'attribut static, et existent
même si aucun objet de la classe n'est crée.
Notons qu’on peut définir un membre donnée statique comme on peut
définir une fonction membre statique. L'accès à ces membres se fait avec
l'opérateur de résolution de portée (::) précédé par le nom de la classe ou d'un
quelconque objet de la classe
Classes et Objets
// Corps de la classe : [Link]
Exemple: #include "Point.h"
// definition obligatoire du membre donné statique
// Interface de la classe : POINT.H
int point::nb_obj;
#ifndef POINT_H Point::Point(int abs, int ord)
#define POINT_H {
x = abs; y = ord;
#include <iostream.h> // utilisé dans affiche() nb_obj++;
class Point{ }
Point::~Point()
int x; {
int y; nb_obj--;
}
static int nb_obj;
void Point::affiche()
public: {
Point(int = 0, int = 0); cout << "(" << x << "," << y << ")" << endl;
}
~Point(); // definition de la fonction membre static
void affiche(); void Point::affiche_nbobj()
{
static void affiche_nbobj();
cout<< ''le nombre d'objets est''<<nb_obj<<endl;
}; }
#endif ----
Classes et Objets
Exemple:
// Programme test
#include "Point.h"
void main()
{ //acces à la fonction membre static avant la création des objets
Point::affiche_nbobj();
// cout << Point::nb_obj ; // erreur : nb_obj est privée
// Appel de la fct membre en utilisant un objet
Point A;
A.affiche_nbobj();
// Appel de la fonction membre statique en utilisant le nom de la classe
Point B(5,6);
Point::affiche_nbobj();
}
Classes et Objets
Les fonctions membres constantes
Les objets, comme les autres types de C++, peuvent être déclarées constants avec
l'attribut const. Dans ce cas, seules les fonctions membres déclarées et définies avec
l'attribut const peuvent être appelées par des objets constants.
// déclarations
Exemple: T u; // instance non constante
class T { … ... const T v; // instance constante
// appels
public:... u.F(…); // OK
type_a F(...); // fct membre ordinaire v.F(…) ; // erreur: instance constante
u.G(…) ; // OK
type_b G(…) const; // fct membre constante v.G(…); // OK
type_c K(const T); // fct avec argument constant
T w;
};
u.K(v); //OK
u.K(w); // OK
v.K(w); // erreur:instance constante et fct non
constante
Remarque: Une méthode constante peut être appelée sur un objet variable ou constant.
Classes et Objets
{ i = v.i;
pi = new int;
*pi = *([Link]);
}
et on refait le même test que dans l'exemple précédent, pour montrer que les problèmes posés par l'initialisation
d'un objet par un autre sont bien résolus.
Classes et Objets
Tableau d'objets
En théorie, un tableau peut posséder des éléments de n'importe quel type. Ainsi
nous pouvons déclarer un tableau de N objets d'une classe T par :
T tab[N];
Or, du fait qu'on ne peu déclarer un objet sans l'initialiser, cette déclaration ne
sera possible que si la classe T admet un constructeur sans arguments (ou
un constructeur dont tous les arguments ont des valeurs par défaut).
Ces mêmes remarques s'appliquent pour les tableaux dynamiques d'objets. Une
déclaration de type :
T * adr = new T[N];
nécessite aussi un constructeur sans arguments.
Classes et Objets
Objet d'objets
Une classe peut comporter un membre donnée de type classe.
Considérons alors la situation suivante, où la classe T comporte un membre
donnée de type classe A :
class A{
……
public:
A(liste_arguments_a);
…
};
class T{
A a;
…
public:
T(liste_arguments);
…
};
Classes et Objets
Objet d'objets (suite)
Lors de la création d'un objet de type T, il y aura appel du constructeur de T
puis un appel du constructeur de A, car la création d'un objet nécessite la définition
de tous les membres données de l'objet (en particulier le membre a de type A).
Par suite, la création d'un objet de type T ne sera possible que si A possède un
constructeur sans arguments.
Pour gérer ce genre de situation, C++ nous offre la possibilité de mentionner, dans la
définition du constructeur de T, la liste des arguments à fournir au constructeur de A
et ce de la manière suivante :
T::T (liste_arguments) : a (liste_arguments_a)
{……}
où liste_arguments_a est une sous liste de liste_arguments, valable pour le
constructeur de A.
Classes et Objets
Fonctions amies
Si une fonction Fct est “amie” (friend) d’une classe C1, alors Fct peut accéder aux
champs privés de C1.
Si une classe C2 est “amie” de C1, toutes les fonctions membres de C2 peuvent
accéder aux champs privés de C1.
Ces déclarations se font dans la définition de C1 :
c l a s s C1
{
...
f r i e n d type-ret Fct( param−de−F ) ;
f r i e n d c l a s s C2 ;
...
};
Classes et Objets
'Friend' en résumé
Les amis d’une classe sont des classes ou des fonctions
Les amis d’une classe peuvent accéder à toutes les méthodes et données membre de
la classe quel que soit le niveau de protection
Les amis d’une classe sont définis à l’intérieur de la classe
Violation parfois utile, mais très souvent déconseillée du principe d'encapsulation
Classes et Objets
La surcharge des opérateurs
En C++, les opérateurs définis pour les types de base sont traités par le
compilateur comme des fonctions, ce qui permet donc, avec la technique de la
surcharge, d'utiliser la plus part d'entre eux avec les types classe
Les opérateurs redéfinissables sont :
. .* :: ?: # ##
Classes et Objets
Véhicule
Véhicule
Avion Voiture Bateau
Avion Voiture Bateau
Jeep Voilier
Jeep Voilier
Hydravion
Heritage
Résumé
Permet de définir une classe qui enrichit ou spécialise une classe existante
On peut dériver de une ou plusieurs classes (héritage multiple très dangereux)
La classe dérivée peut accéder aux membres publics et protégés de la classe de
base
La classe dérivée ne peut pas accéder aux membres privés de la classe de base
Heritage
Syntaxe
Héritage simple:
class MaClass : public MaClass_de_base
{
...
};
Héritage multiple:
class MaClass : public MaClasse_de_Base , public AutreClasse_de_deBase
{
...
};
Heritage
Construction
Quand un objet est construit, tous les constructeurs sont appelés
Les constructeurs des classes de base sont appelés AVANT les constructeurs des
classes dérivées
Exemple : Si A dérive de B qui dérive de C :
Le constructeur de C est appelé
Le constructeur de B est appelé
Le constructeur de A est appelé
Heritage
Exemple
class D
{public :
D(int,int) ;
};
class E : public D // E dérivée de D
{public :
E(int,int,int) ;
};
// initialisation de la classe de base
E::E(int x,int y,int z) : D(x,y)
{
}
Heritage
Constructeurs
CAS 1 : Cas où le constructeur de la classe dérivée est synthétisé par le compilateur
(sans paramètres) : ce constructeur appelle le constructeur par défaut de la classe de
base (appel sans argument du constructeur synthétisé ou d'un constructeur défini
sans paramètres ou dont tous les paramètres ont une valeur par défaut)
class A class A
class A
{ {
{
private: private:
private:
public: public:
public:
A(); A(T1 a1, T2
};
}; a2);
};
class B : public A
class B : public A class B : public A
{
{ {
private:
private: private:
public:
public: ...}; public:
};
};
OK : le constructeur synthétisé de B appelle OK : le constructeur synthétisé de B NON : le constructeur synthétisé de B ne trouve
appelle le constructeur par défaut A pas de constructeur par défaut (défini sans
le constructeur par défaut A (ici synthétisé) paramètres ou avec paramètres par défaut) dans
défini sans paramètres
A
Heritage
Constructeurs (suite)
CAS 2 : Un constructeur explicitement défini de la classe dérivée appelle le
constructeur de la classe de base en accord avec la liste d'initialisation dans l'en-
tête de sa définition. Si la liste ne mentionne pas de constructeur, c'est le
constructeur par défaut qui est appelé (sans paramètres).
Heritage
Appels Constructeurs
class A
{ private:
public:
A(T1 a1, T2 a2);
};
class B : public A // B dérivée de A
{ private:
public:
B(T1 b1, T2 b2, T3 b3);
};
// définition des méthodes
B::B(T1 b1, T2 b2, T3 b3) : A(b1,b2)
{
}
OK : le constructeur de B appelle le constructeur de A précisé dans la liste
d’'initialisation.
Heritage
Appels Constructeurs
class A
{
private:
public:
A();
A(T1 a1, T2 a2);
};
class B : public A
{
private:
public:
B(T1 b1, T2 b2, T3 b3);
};
// définition des méthodes
B::B(T1 b1, T2 b2, T3 b3)
{
}
OK : le constructeur de B appelle le constructeur par défaut (sans paramètres et non synthétisé ici)
de A
Heritage
Appels Constructeurs
class A
{ private:
public:
};
class B : public A
{ private:
public:
B(T1 b1, T2 b2, T3 b3);
};
// définition des méthodes
B::B(T1 b1, T2 b2, T3 b3)
{
}
OK : le constructeur de B appelle le constructeur par défaut
(synthétisé) de A .
Heritage
Appels Constructeurs
class A
{
private:
public:
A(T1 a1, T2 a2);
};
class B : public A
{
private:
public:
B(T1 b1, T2 b2, T3 b3);
};
// définition des méthodes
B::B(T1 b1, T2 b2, T3 b3)
{
}
Lorsqu’une méthode est virtuelle dans une classe de base, elle est toujours
virtuelle dans toutes les classes dérivées
Placerépète r virtual avant le type de retour de la fonction
On virtual dans les classes dérivées pour la clarté (mais ce n’est pas
obligatoire)
Méthode virtuelle
class B : public A
{ public:
B() {} ;
virtual bool IsA() const ;
// virtual est optionnel dans la classe dérivée
};
Méthode virtuelle
SYNTAXE D’IMPLEMENTATION
bool A::IsA() const
{
return TRUE ;
}
A* pA = new A ;
A* pB = new B ;
if (pA->IsA())
cout << " Objet de classe A ";
if (pB->IsA())
cout << " Objet de classe A ";
delete pA ;
delete pB ; // ERREUR !!!!
// Destructeur de B non appelé
Rappel :
En POO, on considère qu’un objet d’une classe dérivée peut « remplacer » un objet
de la classe de base
Méthode virtuelle
Remarque:
Toujours déclarer virtuel le destructeur d’une classe de base destinée à être
dérivée pour s’assurer d' une libération complète de la mémoire.
Pas d’obligation de redéfinir une méthode virtuelle dans les classes dérivées
Possibilité de redéfinir une méthode virtuelle d’une classe de base, par une
méthode virtuelle ou non virtuelle dans une classe Dérivée
Attention!! Nécessité de respecter le prototype de la méthode virtuelle redéfinie
dans une classe dérivée (même arguments et même type retour)
Méthode virtuelle pure
Une méthode virtuelle pure est une méthode virtuelle déclarée dans une classe de
base, mais n’ayant pas d’implémentation dans cette classe
Les autres méthodes de la classe peuvent appeler cette méthode
Méthode virtuelle pure
SYNTAXE DE DECLARATION
Ajouter = 0 à la fin de la déclaration de la méthode
class X
{ // Définition d’une fonction virtuelle pure
// =0 signifie qu’elle n’a pas de définition
// Attention, c’est différent d’un corps vide : { }
virtual bool IsA() const = 0 ;
};
Classe abstraite
Une classe abstraite est une classe qui contient au moins une méthode virtuelle
pure
Les classes dérivées d’une classe abstraite sont abstraites tant que toutes les
méthodes virtuelles ne sont pas implémentées (virtuelles pures)
On ne peut pas créer un objet d’une classe abstraite
Mais possibilité de définir des pointeurs et des références sur une classe abstraite
Quand une classe est abstraite, il est obligatoire d’en dériver et d’implémenter
toutes les méthodes virtuelles pures .
Les entrées-sorties
Introduction
Déjà rencontré :
int n;
cin >> n ; // flot d'entrée cin
cout << n ; // flot de sortie cout
cerr << ''message erreur''; //flot de sortie des erreurs
Flot = « canal » :
recevant de l’information, si flot de sortie
fournissant de l’information si flot d’entrée
Rôle des opérateurs << et >> :
transfert de l’information
formatage (éventuel)
cout = flot prédéfini connecté à la sortie standard (écran)
(en C : fichier prédéfini stdout)
cin = flot prédéfini connecté à l’entrée standard (clavier)
(en C : fichier prédéfini stdin)
Les entrées-sorties
Hiérarchie des classes IO
io s
io s
is t r e a m o s tre a m
is t r e a m o s tre a m
io s t r e a m
ifs t r e a m o fs tr e a m
fs tr e a m
Les entrées-sorties
Classe OSTREAM
cout est un objet de la classe ostream
#include <iostream.h>
ou
#include <iostream>
using namespace std ;
opérateur << surchargé pour les types de base
char ch[20] ;
int len ;
while ([Link](ch,20))
{ len = [Link]() ;
…}
istream & read(char * t,int x);
// lecture de x bytes
char t[5] ;
[Link](t,5) ;
Les entrées-sorties
Connexion d'un flot à un fichier
#include <iostream.h>
#include <fstream.h>
Ecriture dans un fichier :
créer un objet de la classe ofstream (dérive de ostream)
ofstream fic_out ("fic",ios::out) ;
main()
{
Point p1(2,5), p2(1,8),p3 ;
p3 = min(p1,p2) ;
}
Patrons(templates)
Tableau <int,4> t1 ;
Tableau <float,100> t2 ;