0. Le "Monde" orienté-objets
1. 1er programme pour imprimer "Bonjour GIREF!"
2. 2e programme pour additionner 2 nombres entrés par l'usager
3. Opérateurs: +=, -=, ++, --
4. Structures de contrôle
5. Les fonctions
6. Les énumérations
7. Les références: Passage par référence vs par valeur
8. Les arguments par défaut d'une fonction
9. Opérateur de portée "::"
10. Surcharge de fonctions
11. Patrons de fonctions <<template>>
- L'orienté-objets traduit les objets de la réalité
par des objets programmés dans un langage comme C++ ou Java.
- Comme les objets de la réalité, les objets programmés
ont des propriétés et des fonctionnalités possibles/prévues.
- Le langage orienté-objets est basé sur la communication
entre objets.
- Les langages orientés-fonctions comme Fortran ou C sont basés
sur la suite d'appels de fonctions dans lesquelles on passe les données.
- L'orienté-objets transporte les données avec les fonctionnalités.
- On parle souvent de validation des données, contrôle
des données, vérification des données.
- Le langage orienté-objets met beaucoup plus l'accent sur les
données qu'un langage orienté-fonctions.
1. 1er programme pour imprimer "Bonjour GIREF!"
Voici un programme très simple:
#include <iostream>
int main()
{
// Imprime "Bonjour GIREF! à l'écran
(cout)"
cout << "Bonjour GIREF!" << endl;
return 0;
}
Une fois le fichier créé (et nommé par exemple giref.cc), il suffit de taper :
g++ -g -c giref.cc
g++ -o giref giref.opour compiler et créer le lien, puis:
./girefpour exécuter le programme.
- Le #include est un fichier qui sera inclus par le préprocesseur
et qui déclare de multiples fonctionnalités (fonctions, classes,
variables globales) relatives aux flux d'entrée/sortie.
- Dans le standard, on ne met pas de .h pour les fichiers d'en-tête
i.e. #include <iostream> au lieu de #include <iostream.h>
(header files)
- Dans le standard, on devrait aussi ajouter using namespace std
pour que le programme fonctionne
- Il existe 2 types de commentaires:
1- les //qui font que le reste de la ligne
est ignoré
2- les /* avec */ qui font que
tout ce qui est entre les deux est un commentaire
- cout est une variable (objet) du namespace std
qui permet d'écrire à l'écran.
- endl est une fonction du namespace std qui fait
une fin de ligne (à l'écran comme dans un fichier).
2. 2e programme pour additionner 2 nombres entrés par l'usager
#include <iostream>
int main()
{
int lNombre1, lNombre2;
// cin nous permet de lire au clavier
cin >> lNombre1 >> lNombre2;
cout << (lNombre1 + lNombre2) <<
endl;
return 0;
}
- Les opérateurs ++ et -- ont pour effet d'augmenter/décrémenter
de 1 la variable à laquelle on l'applique.
- Il existe 2 versions de l'opérateur ++: préincrément
et postincrément
Exemple :
#include <iostream>
int main()
{
int lNombre1 = 9;
lNombre1 +=1;
lNombre1++;
cout << lNombre1 << endl;
cout << lNombre1++ << endl;
cout << ++lNombre1 << endl;
return 0;
}
Quelle est la sortie de ce programme?
a- if/else
Exemple :
#include <iostream>
int main()
{
int lNombre1(0);
cin >> lNombre1;
if (7 == lNombre1) {
cout << "Le 7
chanceux!" << endl;
}
else {
cout << "Désolé..."
<< endl
}
return 0;
}
b- while
Exemple :
#include <iostream>
int main()
{
int lNombre1(0);
cin >> lNombre1;
// On vérifie que le cin est "valide"...
while (999 != lNombre1 && cin) {
if (7 == lNombre1) {
cout << "Le 7 chanceux!" << endl;
}
else {
cout << "Désolé..." << endl
}
cin >> lNombre1;
}
return 0;
}
c- for
Exemple :
#include <iostream>
int main()
{
int lNombre1(0);
cin >> lNombre1;
for (int i = 0; i < lNombre1; ++i) {
cout << i <<
endl;
}
return 0;
}
d- aiguillage (switch en anglais)
Le switch nous permet de remplacer une série de if/else imbriqués.
Exemple :
#include <iostream>
int main()
{
int lNombre1(0);
cin >> lNombre1;
if (10 == lNombre1) {
cout << "10 moutons.."
<< endl;
}
else if (9 == lNombre1) {
cout << "9 moineaux..."
<< endl;
}
else if (...) {
...
}
return 0;
}
Avec switch:
#include <iostream>
int main()
{
int lNombre1(0);
cin >> lNombre1;
switch (lNombre1) {
case 10 : {
cout << "10 moutons.." << endl;
break;
}
case 9 : {
cout << "9 moineaux..." << endl;
break;
}
// Un "default" dans
un switch c'est comme une assurance!
default: {
cout << "Erreur, pas connu..." << endl;
}
}
return 0;
}
- En général, on essaie d'avoir 1 point entrée
et 1 point sortie, cela rend la fonction plus lisible.
Déclaration vs définition:
- Une déclaration est ce qu'on appelle la
signature ou le prototype de la fonction (son type de retour, son nom,
son nombre de paramètres et le type de chacun des paramètres).
- Une définition est le code même de
la fonction, c'est-à-dire le contenu de la fonction.
Exemple : La norme d'un vecteur x,y,z.
#include <iostream>
double norme(double pX, double pY, double pZ); // Déclaration
int main()
{
double lX = 4.0, lY = 3.0, lZ= 5.0;
cout << norme(lY, lY, lZ) << endl;
return 0;
}
double norme (double pX, double pY, double pZ) // Définition
{
return sqrt(pX*pX + pY*pY +pZ*pZ);
}
- Elles ne sont utilisées qu'à l'occasion.
- Une énumération définit un nouveau type en C++.
Ce n'est PAS un entier.
- Les jours de la semaine:
#include <iostream>
enum Jour {Lundi = 111, Mardi, Mercredi, Jeudi, Vendredi, Samedi, Dimanche};
int main()
{
Jour lMonJourPrefere = Samedi;
cout << lMonJourPrefere << endl;
return 0;
}
7. Les références: Passage par référence vs par valeur
- Le passage par valeur fait une copie de la valeur qui est passée.
Il existe alors 2 copies de la même valeur dans 2 cases mémoires
distinctes.
- Le passage par référence est préférable
au passage par valeur étant donné qu'il ne fait pas de copie
de la variable passée, mais donne une référence à
la case mémoire qu'il occupe. Il existe alors une seule copie de
la valeur et donc une seule case mémoire occupée. La
fonction qui reçoit la variable par référence doit
cependant faire attention car elle peut modifier cette valeur.
- Faire un passage par valeur pour un entier ou un double reste encore
acceptable. Par contre, faire une copie d'une matrice ou d'un maillage
serait inacceptable.
- La référence constante nous permet de n'avoir qu'une
seule copie de la valeur stockée, sans toutefois nous permettre
de la modifier.
Exemple :
#include <iostream>
int calculeCarreParValeur(int pEntier); // passage par valeur
void calculeCarreParReference(int& pEntier); // passage par
référence
int main()
{
int lMaValeur = 10;
cout << "lMaValeur initiale:" <<
lMaValeur << endl;
cout << " Carre par valeur:" <<
calculeCarreParValeur(lMaValeur) << endl;
cout << "lMaValeur:" << lMaValeur
<< endl;
calculeCarreParReference(lMaValeur);
cout << " Carre par reference:" <<
lMaValeur << endl;
return 0;
}
int calculeCarreParValeur(int pEntier) { return pEntier*pEntier; } void calculeCarreParReference(int& pEntier) { pEntier=pEntier*pEntier; }
8. Les arguments par défaut d'une fonction
- On peut définir des arguments par défaut à une
fonction.
- Utile mais dangereux! Attention à la lisibilité du
code!!!
Exemple :
#include <iostream>
double calculVolumeBoite(const double& pLarg = 1,
const double& pHaut = 1,
const double& pProf = 1);
int main()
{
cout << calculVolumeBoite() << endl;
// Quel est le sens de cela?
cout << calculVolumeBoite(2,4) << endl;
cout << calculVolumeBoite(2,4,5) << endl;
return 0;
}
double calculVolumeBoite(const double& pLarg,
const double& pHaut,
const double& pProf)
{
return pLarg * pHaut * pProf;
}
-L'opérateur de portée ( scope en anglais) permet
de spécifier le nom d'une variable, classe ou fonction qui n'est
pas dans la portée actuelle. Par exemple, on pourrait avoir une
variable globale et locale du même nom.
- On utilise aussi l'opérateur de portée pour aller chercher
des définitions dans un namespace (ex. : std::cout).
#include <iostream>
#include <iomanip>
const double PI = 3.14159265358979;
int main()
{
const float PI = 3.14;
cout << setprecision(20)
// Nouveau! ajuste le nombre maximal de décimales écrites.
<< " PI
local: " << PI << endl
<< " PI
global: " << ::PI << endl;
return 0;
}
- On peut avoir plusieurs fonctions qui portent le même NOM, mais
qui ont des paramètres et types de retour différents.
- On peut faire de la surcharge en faisant varier au moins le nombre
de paramètres ou le type de paramètres.
- On ne peut pas surcharger une fonction seulement par le type de retour
(Ah! le C++....).
- Réflexion: l'opérateur + en C, Fortran, C++ est surchargé
selon qu'il s'applique sur un entier ou un double. Hmmm...
Exemple :
int calculCarre (int pNombre);
double calculCarre (double pNombre);
11. Patrons de fonction modèle(template en anglais)
- Les patrons de fonction permettent au compilateur de CRÉER
le code C++ de la fonction, selon le type de paramètre que la fonction
reçoit.
- Cela permet de n'écrire qu'une seule fois le code que l'on
aurait dû répéter plusieurs fois si on avait surchargé
la fonction.
Exemple :
#include <iostream>
#include <iomanip>
template <class PTType>
PTType min(const PTType& pA, const PTType& pB)
{
return (pA < pB ? pA : pB);
}
int main()
{
int lNombre1, lNombre2;
cin >>lNombre1 >> lNombre2;
cout << "Min: " << min(lNombre1,
lNombre2) << endl;
double lDble1, lDble2;
cin >> lDble1 >> lDble2;
cout << "Min: " << min(lDble1, lDble2)
<< endl;
return 0;
}