• Aucun résultat trouvé

Cours 1, 5 mai 2005 A) Les nouveautés de C++ vs C 1

N/A
N/A
Protected

Academic year: 2022

Partager "Cours 1, 5 mai 2005 A) Les nouveautés de C++ vs C 1"

Copied!
1
0
0

Texte intégral

(1)

Cours 1, 5 mai 2005

A) Les nouveautés de C++ vs C

1er but: Rendre la programmationp lus agréable, plus élégante.

2e but: Faire de la programmation orientée objet.

1- // pour insérer un commentaire, jusqu'à la fin de la ligne.

2- Utilisation massive de la clause const (versus #define de C) ex.: const double BLA = 0.2;

- le C n'accepte pas un #define comme borne de tableau - Problèmes majeurs de syntaxe avec le #define

3- Flexibilité des déclarations.

- Permet d'intercaler les déclarations et les instructions.

4- Entrées/Sorties avec cin et cout. ex.: #include <iostream.h>

- Beaucoup plus simple, moins de gestion d'adresses. cout << exp1 << expr2 << etc.

cin >> var1 >> var2 >> etc.

exemple:

#include <iostream.h>

void main() {

int nbPieds, nbPouces;

// Saisie des informations

cout << "Tapez la tailleen pieds et pouces";

cin >> nbPieds >> nbPouces;

// On effectue la conversion

const double PIEDS_EN_METRE = 0.3048; // Rapport de conversion double taille = (nbPieds + nbPouces/12.0) * PIED_EN_METRE;

// On affiche

cout << "La taille en mètre: " << taille << endl; // endl est un retour à la ligne.

}

5- Paramètres par défaut ex.: void afficher(int tab[], nbPers = 3)

- Ce sont les "derniers" sur la liste des paramètres. À l'appel, …

s'il manque d'argements, le C++ utilise les valeurs par défaut. afficher(monTab); // nbPers pas oblig.

6- Surcharge de fonctions

- Des fonctions ayant des syntaxes différentes, mais le même nom.

7- La transmission de paramètres par référence. (IMPORTANT) ex.: int age = 25;

- Très peu d'utilisation des pointeurs, mais plutôt les références. int &z = age; // z est 1 ref. de age // z et age ont mm pos.mémoire exemple:

void determiner(int tab[], int nbElem, int &mini, int &maxi) { mini = maxi = tab[0];

for (int i = 1; i < nbElem; i++) { if (tab[i] < mini) mini = tab[i];

if (tab[i] > maxi) maxi = tab[i];

} }

int age[] = {25, 30, 27, 18, 29}, nbPers = sizeof(age)/sizeof(int);

int ageMin, ageMax;

determiner(age, nbPers, ageMin,ageMax);

cout << ageMin << ageMax << endl;

8- Patron de fonction ex.: template <class T>

void permuter(T &a, T &b) { T tmp=a; a=b; b=tmp; }

(2)

9- Le type «struc» en C++ versus C

- Le type struct est l'ancêtre de l'encapsulation.

- Pas besoin de trainer «struct», le nom de la structure est déjà le nom du type. ex.: Personne p1, p2;

- Dans le corps d type struct, on a le droit d'écrire des fonctions.

exemple:

struct Personne { int age;

double taille, poids;

void saisir() {

cout << "Tapez l'âge…";

cin >> age >> taille >> poids;

}

void afficher(char msg[]="") {

cout << "Infos" << msg << ":" << age << taille << poids << endl;

} }

Personne pers1;

pers1.saisir();

pers1afficher("de la première personne."); // On applique la méthode afficher sur pers1

(3)

Cours 2, 12 mai 2005 A)

Exemple de méthode en C …

int indMax(Employe emp[], int nbEmp, char code) { int ind = 0;

for (int i=1; i <nbEmp; i++)

if ( (code == 'h' && emp[i].nbHr > emp[ind].nbHr) ||

(code == 't' && emp[i].taux > emp[ind].taux ) ) ind = i;

return ind;

}

Une structure (comme Employe) avc des champs d'information et des fonctions membres (écrites dans le corps de cette structure) est l'ancêtre de la notion de «classe», une notion importante de la POO.

B) Introduction à la POO Un tableau est un objet.

Il dispose de carcatéristiques. (couleur, matériau, dimensions …)

Il faut fabriquer un tableau avant de l'utiliser

Il y a plusieurs manières différentes de fabriquer un tableau. (noir/bois/2x6; blanc/plastique/1x2; etc.)

On peut écrire au tableau ¯\

On peut effacer un tableau \____|\ en POO: tableau.ecrire(…) On peut laver un tableau / |/

On peut peinturer un tableau _/

en résumé:

- caractéristiques

- constucteur (instancier) - méthodes

La POO est une manière de programmer basée sur trois concepts:

- encapsulation - polymorphisme - héritage Encapsulation

Mettre dans la même capsule les données et les méthodes pour traiter les données.

L'encapsulation a pour autre but de protéger les données avec des clauses d'accès.

Clause private: 99.99% du temps, les champs d'informations sont privés. (à la classe) Clause publique: La plupart des méthodes sont publiques.

nota: On peut utiliser les «paramètres par défaut» pour combiner quelques constructeurs au lieu de faire une surcharge dans certains cas.

C) Validation de données:

voir: validation.cpp D) La classe string:

Utilisation: #include <iostream.h> #include <iostream>

#include <string> #include <string>

using namespace std;

std::string ch = "Bonjour"; string ch = "Bonjour";

ch.at(3) // ch.substr(0,3) // ch.length() // etc.

(4)

Utilisation de string à partir de chaînes de char:

char ligne[120];

string nom;

cout << "Tapez le nom d'une perosnne");

cin.getLine(ligne, 120, '\n');

nom = ligne; [ou nom = string(ligne) ]

Recherche dichotomique:

int indDicho(int numero[], int nbElem, int aChercher) {

int mini = 0, maxi = nbElem – 1, milieu; int mini = 0, maxi = nbElem – 1;

bool trouve = false; x

while (!trouve && mini <= maxi) { while (mini <= maxi) {

milieu = (mini + maxi) / 2; int milieu = (mini + maxi) / 2;

if (aChercher < numero[milieu]) maxi = milieu – 1;

else if (aChercher > numero[milieu]) mini = milieu + 1;

else trouve = true; return milieu;

}

if (trouve) return milieu; return -1;

else return -1; x

}

(5)

Cours 3, 19 mai 2005

A) Pointeur d'auto-référence (this)

En C++, il y a un pointeur nommé this qui pointe sur l'objet courant (l'objet qu'on est en train de construire ou dans lequel on applique une méthode. Comme this pointe sur l'objet courant, *this EST l'objet courant:

(*this).champ  this->champs (*this).methode()  this->methode() Utilisation 1:

Quand il y a conflit entre le nom d'un champs et d'un paramètre.

ex.: this->rayon = rayon; (dans un constructeur classiue de Cercle) Utilisation 2:

Retourner l'objet courant.

ex.: return *this; (dans une méthode de comparaison par exemple) ex.: class Cercle {

… public:

double surface() {

return PI * rayon * rayon;

}

Cercle plusGrand(Cercle autre) { if (autre.surface() > surface())

return autre;

else

return *this;

} }

nota: autre.surface() > surface()  autre.surface() > (*this).surface()  autre.surface() > this->surface() nota: Cercle plusGrand (Cercle & autre)

fonctionne très bien, on utilise la même zone mémoire plutôt qu'une copie MAIS TRÈS DANGEREUX, donc à éviter !!!

nota: Cercle plusGrand(const Cercle & autre)

ici on évite une copie ET on s'assure qu'il n'y aura pas de modification!

FORTEMENT conseillé.

mais! il y a un prix à payer: il faut rendre les méthodes utilisées const à savoir surface() qui deviendra: double surface() const { … B) Les constructeurs

1- Niveau 0 de la POO

Classe n'ayant pas de constructeur. Dans un tel cas, le C++ fournit un constructeur sans paramètre par défaut, avec des valeurs «inconnues» pour les champs. Alors pour avoir de vraies valeurs pour ces champs, on les saisit souvent au clavier.

2- Niveau régulier des classes

La classe dispose souvent d'au moins un constructeur avec paramètres.

a) Si tous les paramètres sont par défaut, le constructeur joue aussi le rôle du constructeur par défaut.

b) Si ce n'est pas le cas, il est préférable d'avoir un constructeur sans paramètre, même si son corps est vide pour éviter des problèmes à la compilation.

C) Méthodes d'accès et de modification 1- Méthodes d'accès (get):

Pour permettre d'accéder aux champs privés (ou aux infos venant d'un champ privé) en dehors de la classe. Presque tous les langages POO utilisent le mot get dans le nom d'une méthode d'accès. (Obtenir)

(6)

2- Méthodes de modification (set):

Permet de modifier un champs privé depuis l'extérieur de la classe. Le mot set est largement utilisé dans le nom d'une méthode de modification.

ex.: class Etudiant { private:

string codePerm;

int nbCafe;

public:

Etudiant(string codePerm, int nbCafe=1) { this->codePerm = codePerm;

this->nbCafe = nbCafe;

}

char getSexe() {

return codePerm.at(6)>'4' ? 'F' : 'M';

}

int getAge() {

return 105 - atoi(codePerm.substr(8,2).c_str());

}

int getNbCafe() { return nbCafe;

}

void setNbCafe(int nbCafe) { this->nbCafe = nbCafe;

} }

void main() {

Etudiant etud1("CHAN19568003",2), etud2("TREP31128509");

cout << "Sexe de l'étudiant 1:" << ( etud1.getSexe() == 'F' ? "féminin" : "masulin" )

<< endl;

cout << "Âge en 2005 de l'étudiant 2:" << etud2.getAge() << " ans.";

etud1.setNbCafe(etud1.getNbCafe()+3);

} D) Allocation DYNAMIQUE en C++

Les algorythmes, les structures de données et les langages de programmation existent depuis longtemps et évoluent «tranquillement» comparativement à l'évolution des ordinateurs (mémoire, vitesse). Certains soucis ou critiques de l'époque sont moins important et sont compensés par l'évolution des ordinateurs.

Allocation statique:

Les variables ou les tableaux «classiques» utilisent la zone de mémoire statique (lors de la compilation).

Le C et le C++ peuvent utiliser uen zone de mémoire plus large qui s'appelle zone dynamique. Il faut demander son allocation. En C: malloc, avec une syntaxe compliquée. En C++, on utilise le new.

ex.: int * age = new int[2000];

Personne * p = new Personne[150];

- Dans lesquels cas, l'adresse est contenue dans le pointeur *age ou *Personne qui se trouve en mémoire statique.

- Les données se trouvent elles à l'adresse pointée en mémoire dynamique.

Donc: tableau dynamique quand il y a un pointeur (*) et un new.

La borne d'un tableau dynamique:

- Souvent une constante.

- Peut être définie à l'exécution du programme (et non à la compilation).

(7)

La programmation d'un tableau dynamique.

1- On a toute la liberté de le manipuler comme un tableau classique.

2- On peut aussi utiliser des pointeurs et des arythmétique de pointeurs pour manipuler un tel tableau.

ex.: c.f.: class Etudiant

+méthode afficher(string msg="")

void afficher(Etudiant etud[], int nbEtud) { cout << "…";

for (int i=0; i < nbEtud; i++) etud[i].afficher();

}

afficher(etud, nbEtud); // etud, un tableau dynamique d'Etudiants -- OU --

void afficher(Etudiant * p, int nbEtud) { cout << "…";

for (int i=0; i < nbEtud; i++) {

p->afficher(); //  (*p).afficher();

p++; // Pointera vers le prochain élément!

} }

Ajouter un nouvel élément à la fin d'un tableau utilise la même logique avec des données de type différents. On peut donc utiliser un patron (template).

ex.: template <class T>

void ajouter(T tableau[], int & nbElem, T nouvElem) { tableau[nbElem++] = nouvElem;

}

// NE PAS OUBLIER LE & pour que nbElem soit modifié !!!

(8)

Cours 4, 26 mai 2005

A) Surcharge des opérateurs 1- Pourquoi?

Les opérateurs existent surtout entre les infos de types de base. (int, double, char, …)

Pour utiliser les mêmes opérateurs entre deux objets, il faut surcharger. La surcharge permet alors:

o d'utiliser les mêmes algorythmes pour les objets

o d'écrire des patrons de fonctions (appliqués sur les objets) o de profiter de certaines méthodes pré-programmées 2- Comment?

< >= == <<

ex.:

boolean operator < (const Cercle & autre) { return surface() < autre.surface();

}

friend ostream& operator << (ostream&, const Cercle&);  cette ligne s'écrit ds la classe

*La syntaxe reste la même, seul le nom de la classe change ostream& operator << (ostream& sortie, const Cercle& unCercle);

 cette ligne s'écrit hors la classe sortie << "<" << unCercle.rayon << ", " << unCercle.perimetre()

<< ", " << unCercle.surface() << ">";

return sortie;

}

nota: friend: permet au programmeur en dehors de la classe d'accéder au champs privés) important: NE PAS OUBLIER de déclarer surface et perimètre comme const

Conseils: Pour l'intra, basez sur le smodèles (exemples d'aujourd'hui), la surcharge de << a une syntaxe compliquée, parcontre, la manière est la même pour n'importe quel objet.

à noter: Les méthodes et constructeurs sont préférablement déclarés dans la classe, amis implémentés à l'extérieur.

Dans Cercle:

Cercle (double); // Seulement l'entête …

Juste après Cercle:

Cercle::Cercle(double rayon) { // Le :: pour expliquer au compilateur que this->rayon = rayon; // le constructeur est membre de la classe }

double Cercle::perimetre() const { // … même truc pour une méthode return 2 * PI * rayon;

}

bool Cercle:operator < (const Cercle & autre) {

… }

(9)

Liste linéaire chaînée en C++

ex.: DATA = 25, 19, 42

liste[25|][19|][42|x] une liste LIFO (pour programmer une pile / Stack) liste[42|][19|][25|x] une liste FIFO (pour programmer une file d'attente) Déclaration:

class Personne {

… }

struct Element { Personne pers;

Element * suivant;

}

typedef Element * Pointeur;

Pointeur liste;

Utilisation:

cout << liste->pers.getPoids();

liste->pers.setTaille(liste->pers.getTaille() + 0.03);

ex.: Compter le nombre de femmes, d'hommes…

Appels:

cout << leNombre('F',liste);

cout << leNombre('H',liste);

Méthode:

int leNombre(char sexe, Pointeur liste) { int n=0;

while (liste) {

if (liste->pers.getSexe() == sexe) then n++;

liste = liste->suivant;

}

return n;

}

ex.: Supprimer un élément…

Appels:

effacer(3, liste);

Méthode:

void effacer(int numero, Pointeur liste) { Pointeur avant=null, cestLui = liste;

for (int i=0; i<numero; i++) { avant = cesLui;

cestLui = cestLui->suivant;

}

avant->suivant=cestLui->suivant; // Suppression logique

delete cestLui; // Pour libérer la zone mémoire …

}

ex.: Réduire de 2kg le poids du premeir homme de la liste Pointeur p = liste;

while (p && p->pers.getSexe() != 'M') p=p->suivant;

p->pers.setPoids(p->pers.getPoids() – 2.0);

(10)

Cours 5, 9 juin 2005 A) …

Constructeur de recopie:

PileEntier a, b=a; -ou- PileEntier c(a); Constructeur de recopie utilisé.

PileEntier d; d = a;  Pas la même chose! C'est simplement la surcharge de l'affectation.

PileEntier::PileEntier(const PileEntier & autre) { indiceSommet = autre.indiceSommet;

sommet = new int[MAX_ELEM = autre.MAX_ELEM]; // new, pour créer la copie!

for (int i=0; I < indiceSommet; i++) sommet[i] = autre.sommet[i];

}

Destructeur: - au maximum un par classe

~PileEntier();

PileEntier::~PileEntier(); { delete[] sommet;

}

void main() {

PileEntier pile1;

… if (…) {

PileEntier pile5;

}    appel automatique au destructeur à la fin du bloc! (pour pile5)

}    appel automatique au destructeur à la fin du bloc! (pour pile1)

Piles:

empiler (push): ajouter un élément au sommet de la pile

dépiler(pop): retirer et retourner l'élément au sommet de la pile consulter(peek): retourner dans enlever l'élément au sommet de la pile combien d'éléments …

void empiler(int valeur);

int depiler();

void PileEntier::empiler(int valeur) {

sommet[indiceSommet++] = valeur;

}

int PileEntier::depiler() {

sommet[--indiceSommet]; // Pas de delete! c'est un tableau, pas une liste chaînée

} // (on fera un delete sur le tableau complet…)

B) Patron de classes

On peut écrire un seul patron de classe au lieu de plusieurs classes pour les piles par exemple. On a donc des piles de caractères aussi bien que des piles d'entier.

Dans la librairie standard de C++, STL on a des patrons de liste, de piles, etc.

(11)

C) Récursivité

Une fonction est récursive quand elle s'appelle. Cett notion vient des méthématiques. Il est extrèmement simple de programmer des version des solution mathématiques récurrentes.

Factorielle:

n! / 1 si n=0 ou 1

\ sinon: (n-1)!*n

 int factorielle(int n)

if (n==0 || n==1) return 1 else return factorielle(n-1) * n;

}

Suite de Fibonacci:

f(n) … 1, 1, 2, 3, 5, 8, 13, 21 …

 int fibonacci(int n) { // Le type int est très limité, même long est trop petit si n > 47 ! if (n==0 || n==1) return 1

else return fibonacci(n -1) + fibonacci(n – 2);

}

nota: La récursivité est simple, mais coûteuse (très long pour faire un calcul) nota: la fonction rand() est limitée entre 0 et RAND_MAX, qui lui vaut 32767…

srand(time(0));  à ajouter pour intialiser l'horloge comme germe aléatoire.

void quickSort(int tab[ ], int gauche, int droite) {

if (gauche < droite) { // au moins 2 éléments

int indPivot;

partitionner(tab, gauche, droite, indPivot); // Pivot est la pos. finale du 1er élément quickSort(tab, gauche, indPivot-1);

quickSort(tab, indPivot+1, droite);

} }

quickSort(t, 0, nbElem-1);

// Rapide parce que à chaque tour de boucle, on trie des tableaux de plus en plus petits…

voir le quickSort.cpp pour les fonction permuter et partitionner.

La récursivité, si on n'a pas de formule mathématique, il faut se baser sur:

- Les observations - La pratique - Les modèles

Condition d'arrêt: Quand termine-t-on le processus récursif?

Réduction du problème:Afin de forcer l'arriver à la condition d'arrêt. (/, mod, 1 de moins, etc.) int sommeChiffres(int n) {

// Condition d'arrêt

if (n < 10) return n; // (un seul chiffre, yé!) // Réduction du problème

else return n % 10 + sommeChiffres(n / 10); // (le problème est réduit d'un chiffre!) }

int chiffreDeDroite(int n, int k) ~ if (k ==1) return n % 10;

else return chiffreDeDroite(n / 10, k-1) }

Autres exemples: recurs.cpp

(12)

Cours 6, 16 juin 2005 A) Patron de classes

class PileEntier { class PileCar {

private: private:

int * sommet; char * sommet;

int MAX_ELEM; int MAX_ELEM;

int indiceSommet; int indiceSommet;

public: public:

… …

void empiler(int valeur); void empiler(char empiler);

} }

void PileEntier::empiler(int valeur) {

sommet[indiceSommet++] = valeur;

Patron  template <class T>

class Pile { private:

T * sommet;

… pblic:

void empiler(T valeur);

}

template <class T>

void Pile<T>::empiler(T valeur) {

sommet[indiceSommet++] = valeur;

}

Utilisation  Pile<int> divi(50); // Pile vide d'au maximum 5 entiers créer(100, divi);

afficher(divi);

voir creer(int nombre, Pile<int> & divi) {

for (int candi = 1; candi <= nombre; candi++) if (nombre % candi == 0)

divi.empiler(candi);

}

void afficher(Pile<int> divi) {

if (Pile.estVide()) cout << "Pile vide\n";

else {

cout << "Le contenu…" << divi.valSommet() << " sont:\n";

for (int i = 0; i < divi.getNbElem(); i++)

cout << I << ")\t" << divi.get(i) << endl;

Utilisation 2  Pile<char> pile = creer(souhait);

Pile<char> créer(string chaine) { Pile<char> p;

for (int I = 0; I < chaine.length(); i++) { if (chaine[i] >= 'a' && chaine[i] <= 'z')

etc.

(13)

B) Le patron list de la librairie standard (une liste doublement chaînée) STL: Standard Template Library

liste[\/][\/][\/][\/][\/]X  Théorie

[e1] [e2] [e3] [e4] [e5] [fin fictive]  En pratique, que cette partie d'intéressante 95% du temps on ne se déplace que dans un sens malgré tout.

liste.front() : référence vers le premier élément liste.front() += 8;

liste.back() : référence vers le dernier élément liste.back() *= 2;

Un itérateur (ici associé à une liste) a pour but:

1- de se positionner à un emplacement de la liste 2- de se déplacer avec ++ ou –

3- *il est l'élément à l'emplacement de l'itérateur.

liste.begin() est un itérateur qui est positionné sur le premier élément

liste.end() est un itérateur qui est positionné après le dernier élément (fin fictive) liste.rbegin() est l'itérateur qui est positionné SUR le dernier élément

for (list<int>::iterator il=list.begin(); il != liste.end(); il++) cout << *il << endl;

liste.back() /= 3;

-ou-

il = liste.end(); // Positionner sur la fin fictive il--; // Positionner sur le vrai dernier

*il /= 3;

-ou-

*liste.rbegin() /= 3;

exemple:

int age[] = {45, 19, 26, 30, 28};

nbPers = sizeof(age) / sizeof(int);

1) créer liste LIFO 2) afficher le contenu

3) doubler 1er élément / réduire de 5 le dernier élément 4) ajouter 59 au début

5) chercher 19, 30, 27 6) supprimer 26 7) trier la liste voir liste.cpp

Nota: Si on cherche un pays à partir de son nom…

… il = find(liste.begin(), liste.end(), Nation(nomCherche));

 Il faut un constructeur contenant la clé de recherche!

 Il faut surcharger l'opérateur d'égalité ==

list<int>::iterator il = liste.begin(); // Enlever seulement le premier «26»

while (il != liste.end() && *il != 26) il++; // …

liste.erase(il); // …

liste.unique(); // Élimine tous les doublons.

liste.sort(); // Pour trier… penser à surcharger < au besoin !

sort(liste.begin(), liste.end()); // #include <algorithm>

Autre manière de fonctionner: typedef liste<Fraction> listeFraction;

typedef liste<Fraction>::iterator Iterliste;

Nota: int PGCD(int a, int b) {return (a%b != 0 ? PGCD(b, a%b) : b)} // Permet de simplifier des fractions!

(14)

Cours 7, 23 juin 2005 A) Héritage simple

Un des concepts de la POO (un fils est tel que le père avec des ajouts). En POO on essaie de réutiliser le codage déjà existant. C'est ce que permet l'héritage. Quand on parle d'héritage simple, on dérive d'une classe uniquement.

Dérivé, sous-classe, etc // Classe de base Carre est une classe dérivée de Rectangle Héritage multiple:

ex.: Informaticiens  Opérateur / Analyste / Programmeur / …  Programmeur+Analyste ! ex.: Avant STL, pour faire une liste de Nations, on dérivait de Liste et Nation …

Dans la plupart des utres langages, on ne permet pas l'héritage multiple (Java, …). Et même en C++, aujourd'hui, on utilise STL plutôt que l'héritage multiple la plupart du temps. On se sert plutôt des patrons de fonction (list<Nation>).

exemple:

class Rectangle { private:

double longueur, lageur;

public:

void afficher(string msg="");

}

class RectangleVisible : public Rectangle { private:

bool estVisible;

public:

RectangleVisible(double longueur, double largeur, bool estVisible):

Rectangle(longueur, largeur) { // : sert à initialiser...(constr. base) this->estVisible = estVisible;

}

void afficher(sring msg="") { Rectangle::afficher(msg);

cout << "est-il visible?" << (estVisible ? "oui" : "non");

} }

class Carre : public Rectangle { // Pas de champs supplémentaire … public:

Carre(double cote) : Rectangle(cote, cote) { };

double diagonale() {

return getLongueur() * sqrt(2.0); // !OU!, remplacer private par protected

} // … dans la classe mère!  longueur...

}

test:

Rectangle rect(1.8, 0.9);

rect.afficher("du rectangle rect");

RectangleVisible rv(8.5, 4.3, true);

rv.afficher("du rectangle visible rv);

Rectangle *p;

p = &rect; // p pointe vers rect

p->afficher("du rectangle pointé par p"); // ok

p = &rv; // rv est un RectanlgeVisible  est aussi un Rectangle

//  compile ok.

p->afficher("de rectangle visible pointé par p"); // On perd les infos de la classe dérivée !!!

//  C'est le afficher de Rectangle qui est appelé !!!

(15)

Conclusion:

Si on ne fait rien de spécial, le C++ travaille avec la ligature statique (associé à la compilation).

Comme p est déclaré comme pointeur vers Rectangle, alors on appelle les méthodes de Rectangle.

Pour régler le problème de ligature statique, on veut une ligature dynamique. (Associé à

l'exécution plutôt qu'à la compilation). Malgré que p pointe vers un Rectangle, on veut que s'il pointe par après un Carre ou un RectangleVisible, ce soit leurs méthodes qui soient appelées. Le C++ propose la notion de fonction virtuelle pour la ligature dynamique.

La fonction afficher apparaît dans l'exemple sous trois formes diférentes. C'est la notion de polymorphisme en POO: la capacité de se présenter sous plusieurs formes. Le but étant d'utiliser la bonne méthode sur le bon objet.

On rencontre le polymorphisme en C++ quand il y a surcharge de fonctions ou d'oérateurs, quand on utilise this, un patron ou une fonction virtuelle.

Fonction virtuelle:

On ajoute devant la définition d'une fonction qui sera surchargée le mot clé virtual.

Utilisation recommendée: virtuel2.cpp

La surcharge de la fonction «dédoublée» sera d'abord exécutée puis la fonction de base.

B) Au sujet des listes:

Observer les list*.cpp, On comprend comment créer et manipuler une liste. On remarque (important) qu'en C++

on utilise largementles itérateurs pour manipuler une liste. Un pointeur, au point de vue pratique, est assez semblable au cas de pointeur vers le type char.

ex.: ['9'|'1'|'1'|'\0']

for (char *p = urgent; *p != '\0'; p++) cout << *p;

vs.:

for (list<int>::iterator il = liste.begin(); il != liste.end(); il++) cout << il;

Suppression dans une liste:

liste.remove(42); // Tous les 42 sont supprimés de la liste for(il = liste.begin(); il!= liste.end() && il != 15; il++)

liste.erase(il); // Efface uniquement le premeir 15 de la liste.

Recherche d'un élément dans une liste:

#include <algorithm>

/* Dans la classe du contenu de la liste (Nation, Employe, …), s'assurer d'avoir un constructeur pour la recherche et surcharger l'opérateur d'égalité. */

// find(il1, il2, objetRecherche); // On cherche…

find(liste.begin(), liste.end(), Nation("Australie");

Trier une liste: (deux choix)

- surcharger l'opérateur < et appliquer liste.sort();

- choix 2:

# include <algorithm>

/* surcharger < */

sort(liste.begin(), liste.end());

Modifier un élément:

// Positionner il vers l'élément voulu … il->set(…);

(16)

Nota: liste.unique()  Élimine les doublons!

Exemple de supression:

(1 2 3 5 10 20 25 50 100)

void supprimer(list<int> &liste, int k) { // une proposition à réfléchir

for (list<int>::iterator il = liste.begin(); il != liste.end(); il++) if (*il % k == 0)

liste.erase(il); // va planter!!! après le erase, le il sera placé n'importe où!!!

// parcontre, la fonction erase retourne un autre iterateur!

Solution possible pour un patron de classe des triplets:

Triplet t1(5, 8, 2);

cout << "triplett1:" << t1;

template <class T>

class Triplet { private:

T a, b, c;

public:

Triplet(T,T,T);

friend ostream& operator << (ostream& const Triplet &);

}

Triplet<T>::Triplet(T a, T b,T c) { this->a=a, this->b=b, this->c=c;

}

template <class T>

T Triplet<T>::plusPetit() const { if (a < b && b < c)

return a;

else if (b < c) return b;

else return c;

}

template <class T>

ostream& operator << (ostream& sortie, const Triplet<T> & unTrip) { sortie << etc.

return sortie;

}

(17)

Cours 8, 30 juin 2005 A) Classe abstraite

… Exemple des formes géométriques et du calcul de la surface et du périmètre.

Une classe est abstraite quand elle contient au moins une méthode abstraite.

En C++ on dit «Fonction virtuelle pure».

Le C++ interdit d'instancier un objet de classe abstraite.

Parcontre, une classe abstraite peut avoir un (des) constructeurs (car une sous-classe peut s'en servir!) ex.:

Figures fg[ ] = { Cercle(8.5), Rectangle(7.3,5.9), Rectangle(3.4,5.6), Cercle(8.5), Cercle(7.1) }

On peut ensuite facilement calculer la surface totale dans uen boucle.

B) Fichier binaire

Type texte: Chaque composant est une ligne de texte (!).

- On lit une ligne * on perd de l'espace (blancs) - On extrait le champs * on perd du temps

- On fait la conversion * on perd du temps

-

etc. ** peut être créé ou lu par un éditeur de texte.(ou autre logiciel) Type binaire: Une suite d'octets.

- Si la taille d'un composant (type de base, structure ou objet) est fixe, on est capable d'écrire ou de relire composant par composant avec une syntaxe assez simple.

- Voir binaire1.cpp et binaire.cpp

Écriture Lecture

Étape 1: Nommer et ouvrir.

ofstream aCreer(nomFichier, ios::out|ios::binary); ifstream aLire(nomFichier, ios::in|ios::binary);

Étape 2: Écrire son contenu (souvent dans une boucle).

aCreer.write( (char *) &item, nbOctets); while(aLire.read( (char *) &item, nbOctets ))

Étape 3: Fermer.

aCreer.close(); aLire.close();

 nbOctets est déterminé par un sizeof(…) C) Arguments de la fonction main

ex.:

#include <iostream>

using namespace std;

void main(int nbArg, char * arg[]) {

cout << "Le nombre d'arguments de main : " << nbArg << endl;

for (int i = 0; i < nbArg ; i++)

cout << "arg[" << i << "] = " << arg[i] << endl;

}

 Le nom du logiciel lancé est l'argument 0 !!! (don nombre tjrs >= 1)

Références

Documents relatifs

Participation au projet de déploiement de la plate-forme LANDESK Prise de main à distance avec Dameware NT, VNC, LANDESK Support niveau 2 auprès des utilisateurs (1200 postes

Origano matt lacquered base unit with central groove, MLL 0.7 washbasin and Cristalplant mirror, 2.8 cm thick, with top and bottom LED backlighting on both sides... 46

Cette villa de plain-pied dispose de différentes entrées. Dès votre entrée, vous faites face à un gigantesque espace de vie de plus de 80 m2. Il comprend un salon, une cuisine,

| Sassenage| Lycée Roger Deschaux| 04 76 85 96 10JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ | Vienne| Lycée Galilée| 04 74 53 00 13JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ | Voiron| LP

// creation d’une instance d’objet de type PolyLineaire /* Rappel : une creation d’objet se fait par

Proton, créé en 1983, naît de la volonté du Premier Ministre, le Dr Mahathir, de créer une industrie automobile nationale, autant pour des raisons économiques que pour des raisons

B.A.C PROFESSIONNEL TECHNICIEN CONSTRUCTEUR BOIS 2015 - 2016 Fabrication d’un ouvrage / Dossier technique 3/11..  L’ouvrage à réaliser est une cabane en ossature bois qui

Cette villa de plain-pied dispose de différentes entrées. Dès votre entrée, vous faites face à un gigantesque espace de vie de plus de 80 m2. Il comprend un salon, une cuisine,