Formation C++
Hello World !
#include <iostream>
/* Commentaire
sur plusieurs lignes */
int main()
{
//Affiche hello world
std::cout << "Hello World !“
<< std:endl;
}
Nouveautés de syntaxe en C++ Surcharge de fonctions, d’opérateurs Références
Namespace (non abordé) Fonctions templates (non abordé)
Surcharge de fonction
void f(int i) {}
int f(double i) {}
void f(int a,int b) {}
// ERREUR :
// Diffère uniquement par
// le type de retour
double f(int i) {}
Attention aux ambiguïtés
void f(int a, double b) {}void f(double a, int b) {}int a,b;f(a,b); // ??f((double)a,b); //ok
Le mieux est encore de ne pas écrire deux fonctions aux paramètres si proche l’un de l’autre !
Opérateurs
Mathématiques : +, -, *, /, %, ++, --
Logiques : &&, ||, !, ==, !=, <, >, <=, >=
Données : *, &, ->
Binaire : &, |, ^, ~, <<, >>
Assignation : =, *=, /=, %=, +=, -=, <<=, >>=, &=, |=, ^=
Tous surchargeables.
Références
Permettent de passer la variable plutôt que la copie.
Evite la recopie de la variable (gain en rapidité pour de grosses structures).
Permet de simplifier l’écritures de fonctions qui écrivent dans une variable.
Référence
void Double(int x)
{
x*=2;
}
int a=2;
Double(a); //a==2
void Double(int& x)
{ x*=2; }
Double(a); //a==4
void Double(int* x)
{ *x*=2; }
Double(&a); //a==4
Qu’est ce qu’un objet ?
Un type qui regroupe des informations (membres), et qui offre des moyens de les traiter (grâce à des méthodes).
Exemple : objet joueur
Membres :
points de vie
envie de manger
état (mort ?)
Méthodes :
Attaqué par
Mange
Comment définir un objet en C++class CJoueur
{
public:
void AttaqueDe(CJoueur& J)
{
Vie -= J.Vie; EnvieManger += 10;
Mort = ((Vie<=0)||(EnvieManger>=100));
}
void Mange() {EnvieManger=0;}
int Vie, EnvieManger; bool Mort;
};
Structure des fichiers d’un projet C++Header (.h)
Header (.h)
Code (.cpp)
Code (.cpp)
Objet (.o)
Objet (.o)
Executable
Compilation
Link
Les erreurs
Compilation Syntaxe (erreurs) Warnings
Linkage Fonctions et variables déclarées, non
implémentées Exécution
Segfault
Organisation des fichiers
Joueur.h :
class CJoueur
{
public:
void AttaqueDe(CJoueur& J);
void Mange();
int Vie, EnvieManger;
bool Mort;
};
Joueur.cpp :
void CJoueur::AttaqueDe(CJoueur& J)
{
Vie -= J.Vie;
EnvieManger += 10;
Mort = ((Vie<=0)||(EnvieManger>=100));
}
void CJoueur::Mange()
{ EnvieManger=0; }
Pré compilateur
Joueur.h :
#ifndef JOUEUR_H
#define JOUEUR_H
Class CJoueur
{/* … */ };
#endif
Joueur.cpp :
#include “Joueur.h”
void CJoueur::AttaqueDe(CJoueur& J)
…
Utilisation de l’objet
CJoueur J;
J.Mort=false;
J.Vie=100;
J.Mange();
CJoueur* p=&J;
(*p).Vie=100;
p->Vie=100;
p->Mange();
Constructeur – destructeur
Initialisation des données : on veut qu’à la création de la variable notre joueur soit vivant sans avoir besoin de le dire !
Constructeur : fonction appelée à la création de l’objet (pour l’initialisation)
Destructeur : fonction appelée à la destruction de l’objet
Constructeur – destructeur
class CJoueur
{
public:
CJoueur()
{
Vie=100; EnvieManger=0;
Mort=false;
}
~CJoueur() { }
};
new et delete, création dynamique d’objetsmalloc et free (du C) ne peuvent être utilisés car on a
besoin d’appeler le constructeur et le destructeur de l’objet
new T; retourne un pointeur vers une zone de donnée allouée par l’OS pour stocker un objet de type T.
delete p; informe l’OS que la mémoire préalablement allouée par un new n’est plus utile.
Toujours autant de new que de delete !
(règle sans aucune exception !)
Membres privés, publics
Cacher des membres et des propriétés à l’extérieur
Assurer que les données ne seront pas modifiées par l’extérieur
Indiquer à l’utilisateur les membres et méthodes dont il aura besoin
Conseil : mettre les membres en privé, avec au besoin des méthodes Get-Set
Membres privés, publicsclass CJoueur
{
public:
CJoueur();
~CJoueur();
void AttaqueDe(CJoueur& J);
void Mange();
bool IsDead();
private:
int Vie, EnvieManger;
bool Mort;
};
Dérivation
Créer un nouvel objet, plus spécifique, à partir d’un objet de base
CJoueur -> CJoueurHumain, CJoueurZerg, CJoueurProtoss
(CJoueur&)CJoueurHumain (CJoueurHumain&)CJoueur
Dérivation
class CJoueurZerg
: public CJoueur
{
public:
void SayGrrrgg();
};
CJoueurZerg Zergling;
CJoueur J;
Zergling.Mange();
J.AttaqueDe(Zergling);
Zergling.SayGrrrgg();
CJoueur* p=&Zergling;
p->SayGrrrgg(); //Error
Fonctions virtuelles
CJoueurHumain, CJoueurProtoss et CJoueurZerg ne mangent pas de la même façon. Pourtant on veut que tout CJoueur puisse manger.
Fonctions virtuelles
class CJoueur
{
public:
virtual void Mange()
{
EnvieManger=0;
}
};
class CJoueurZerg
:public CJoueur
{
public:
void Mange()
{
SayGrrrgg(); CJoueur::Mange();
}
};
Fonctions virtuelles
CJoueurZerg Over;
CJoueur J;
CJoueur* P=&Over;
J.Mange();
Over.Mange();
P->Mange();
Fonctions virtuelles pures
On ne sait pas définir CJoueur::Mange, on veut que les classes dérivées soient contraintes d’implémenter Mange()
class CJoueur
{
public:
virtual void Mange()=0;
};
Fonctions virtuelles pures
class CJoueurZerg
:public CJoueur
{
public:
void Mange()
{
SayGrrrgg(); EnvieManger=0;
}
};
CJoueurZerg Hydra;
Hydra.Mange();
CJoueur J; //Erreur
CJoueur* P=&Hydra;
P->Mange(); //OK
Fonctions virtuelles pures
class CJoueurHumain
:public CJoueur {};
class CCapitaine
:public CJoueurHumain
{
public:
void Mange()
{ /* … */ }
};
CJoueur J; //Erreur
CJoueurHumain J; //Erreur
CCapitaine Capitaine;
CJoueur* P=&Capitaine;
P->Mange(); //OK
class CMatrix {
public:
CMatrix() {}
CMatrix(const CMatrix& m);
double& operator()(int i,int j) {return Datas[i][j];}
CMatrix& operator=(CMatrix& m);
CMatrix& operator*=(double d);
CMatrix& operator+=(CNmatrix& m);
CMatrix operator+(CMatrix& m);
CMatrix operator-();
friend CMatrix operator*(double r,CMatrix& m);
private:
double Datas[3][3];
};
CMatrix::CMatrix(const CMatrix& m) { *this=m; }
CMatrix& CMatrix::operator=(CMatrix& m);
{
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
(*this)(i,j)=m(i,j);
return *this;
}
CMatrix& CMatrix::operator*=(double d)
{
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
(*this)(i,j)*=d;
return *this;
}
CMatrix CMatrix::operator*(double r,CMatrix& m)
{
CNmatrix R(m);
return R*=r;
}
CMatrix& CMatrix::operator+=(CNmatrix& m)
{
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
(*this)(i,j)+=m(i,j);
return *this;
}
CMatrix CMatrix::operator+(CMatrix& m)
{
CMatrix R(*this);
return R+=m;
}
CMatrix CMatrix::operator-() { return -1*(*this); }
Analyse d’une opération
CMatrix a,b,c;
//Initialisation de a et b…
c=2*a+b;
c.operator=(operator*(2,a).operator+(b));
CMatrix d=c;
CMatrix d(c);
La STL
Standard Template Library Bibliothèque standard (elle fait partie de la
norme C++) qui offre des types de variables et des fonctions utiles
Toutes les noms sont précédées de std::
std::string, std::vector, std::list, std::sort…
std::string (<string>)
Chaîne de caractères
std::string MonNom=“Vincent”;
MonNom.size()==7;
MonNom+=“ Lascaux”;
MonNom==“Vincent Lascaux”;
MonNom[0]==‘V’; MonNom[3]==‘c’;
std::vector (<vector>)
Container standard : tableau (acces rapide au n° élément (O(1)), insertion lente (O(n)) )
std::vector<int> Tableau;Tableau.resize(20);Tableau[0]=12; Tableau[1]=42;for(int i=2;i<20;i++) Tableau[i]=i*i;
Tableau.reserve(40);for(int i=0;i<20;++i)
Tableau.push_back(12);
std::list (<list>)
Une liste chaînée (acces lent au n° élément (O(n)), insertion rapide (O(1)) )
std::list<std::string> Liste;
Liste.push_back(“CNedra“);
Liste.push_back(“rulez”);
Liste.push_front(“See how “);
//Liste = [“See how”, “CNedra”, “rulez”]
Itérateurs
Permet de parcourir un container Unifie la syntaxe (tous les containers se
parcourent de la même façon, que ce soient tableau, liste, arbre ou autre)
S’utilise comme un pointeur (le container pointe sur un objet du container).
Itérateurs
int Somme=0;
for(std::vector<int>::iterator it=Tableau.begin(); it!=Tableau.end();it++)
Somme+=*it;
int Somme=0;
for(std::list<int>::iterator it=Liste.begin(); it!=Liste.end();it++)
Somme+=*it;
Les avantages de la STL
Ne pas réinventer la roue Eviter des bugs
(memory leaks… : la STL ne bug pas) Se simplifier la vie
Opérateurs usuels (=, ==, <, >…) Efficacité
D’écriture du code Du code
Tutoriaux
Thinking in C++ STL : aide de tout bon compilo,
tutoriaux sur le net, MSDN
Google est ton ami
Un peu de C
Les variables
int a;
int a,b;
int a=2;
int a=2, b=3;
int Puissance4(int x)
{
int carre;
carre=x*x;return carre*carre;
}
Quelques exemples
//Retourne le double de x
int Double(int x)
{
return 2*x;
}
Types entiers :
char, int, short, long
Types réels :
float, double
Evite d’utiliser le préfixe std:: avec la ligne
using namespace std;
#include <iostream>
int main()
{
std::cout << “Hello World\n”;
return 0;
}
Pointeurs
Un type de variable stockant l’adresse d’une zone en mémoire
Une valeur particulière : NULL
int a;
int* p;
p=&a;
*p=2; //a==2
a=3; //*p==3
Surtout utile pour les structures classiques (listes chaînées, arbres binaires…)
Contrôle du flux
Condition if – else Boucles do-while, while Boucle for
Condition
Le type d’une condition est bool, il peut prendre les valeurs true ou false. Les nombres entiers peuvent être testée :0 false, autre nombre true
<, <=, >, >=, ==, !=&&, ||, !
A==3 && B==2 A==((3 && B)==2) (A==3) && (B==2)
if - else
int sign(int x)
{
if(x<0)
{
return -1;
} else {
return 1;
}
}
int sign(int x)
{
if(x<0) return -1;
else return 1;
}
Boucles do-while et while
int Age;
do
{
cout<<"Quel est votre age ?“<<endl;
cin >> Age;
}while(Age<=0);
while(OnmEcoute())
{ Dit_un_mot(); }
Boucle for
int i;
for(i=0;i<10;i++)
{
cout << “10 fois”;
}
for(int i=0;i<10;i++)
cout << “10 fois”;
for(Init; Condition; Step) { Code }
Init; while(Condition) {Code; Step;}
Transtypage (cast)
Changer le type d’une expression
double a; (int)a;
int a; (double)a;
Transtypage implicite
double Carre(double a) {return a*a;}
Carre(2); //Carre((double)2), Carre(2.)
const
Problème des références : on ne sait plus si l’argument sera ou non modifié
const permet d’indiquer que l’argument ne pourra être modifié
Erreur à la compilation si une fonction modifie un argument const (par une affectation, ou l’appel d’une méthode non const)