Aller au menu - Aller au contenu

[Plan du site] Vous êtes ici --- > Le Site du Zéro > Les tutoriels > Officiels > Programmation > Apprenez à programmer en C++ ! > [Théorie] La Programmation Orientée Objet > La magie de la POO par l'exemple : string > Lecture du tutoriel

La magie de la POO par l'exemple : string

Avatar
Auteur : M@teo21
Note : 18 / 20 (29 votes)
Visualisations : 127 887


Plus d'informations Plus d'informations
Nous attaquons maintenant la 2ème moitié de la première partie du cours de C++. Et comme dans la vie rien n'est jamais simple, cette "deuxième moitié" sera la plus grosse et... la plus délicate aussi :D

Nous allons maintenant, et dans les chapitres suivants, découvrir la notion de programmation orientée objet (POO). Comme je vous l'ai dit plus tôt, c'est une nouvelle façon de programmer. Ca ne va pas révolutionner immédiatement vos programmes, ça va vous paraître un peu inutile au début (comme lorsque vous aviez découvert les pointeurs ;) ), mais faites-moi confiance : faites l'effort de faire ce que je dis à la lettre, et bientôt vous serez bien plus efficaces lorsque vous programmerez.

Ce chapitre va vous parler des 2 facettes de la POO, le côté utilisateur et le côté créateur.
Puis, je vais faire carrément l'inverse de ce que tous les cours de programmation font (je sais je suis fou :p ) : au lieu de commencer par vous apprendre à créer des objets, je vais d'abord vous montrer comment les utiliser avec pour exemple le type string fourni par le langage C++.
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Des objets... pour quoi faire ?

Ils sont beaux, ils sont frais mes objets



S'il y a bien un mot qui doit vous frustrer depuis que vous en entendez parler, c'est celui-ci : objet.

Encore un concept mystique ? Un délire de programmeurs après une soirée trop arrosée ?
Non parce que franchement, un objet c'est quoi ? Mon écran est un objet, ma voiture est un objet, mon téléphone portable... ce sont tous des objets !


Bien vu, c'est un premier point :)
En effet, nous sommes entourés d'objets. En fait, tout ce que nous connaissons (ou presque) peut être considéré comme un objet. L'idée de la programmation orientée objet, c'est de manipuler des éléments que l'on appelle des "objets" dans son code source.

Mais concrètement, c'est quoi ? Une variable ? Une fonction ?


Ni l'un, ni l'autre. C'est un nouvel élément en programmation.
Pour être plus précis, un objet c'est... un mélange de plusieurs variables et fonctions o_O

Ne faites pas cette tête-là, vous allez découvrir tout cela par la suite ;)


Imaginez... un objet



Pour éviter que ce que je vous raconte ressemble à un traité d'art moderne conceptuel, on va imaginer ensemble ce qu'est un objet à l'aide de plusieurs schémas concrets.
Les schémas 3D que vous allez voir par la suite ont été réalisés pour moi par l'ami Nab, que je remercie d'ailleurs vivement au passage.


Imaginez qu'un programmeur décide un jour de créer un programme qui permet d'afficher une fenêtre à l'écran, de la redimensionner, de la déplacer, de la supprimer... Le code est complexe : il va avoir besoin de plusieurs fonctions qui s'appellent entre elles, et de variables pour mémoriser la position, la taille de la fenêtre, etc.
Il met du temps à écrire ce code, c'est un peu compliqué, mais il y arrive. Au final, le code qu'il a écrit est composé de plusieurs fonctions et variables. Quand on regarde ça pour la première fois, ça ressemble à une expérience de savant fou à laquelle on ne comprend rien :


Image utilisateur



Ce programmeur est content de son code et veut le distribuer sur internet pour que tout le monde puisse créer des fenêtres sans passer du temps à tout réécrire. Seulement voilà, à moins d'être un expert en chimie certifié, vous allez mettre pas mal de temps avant de comprendre comment tout ce bazar fonctionne.

Quelle fonction appeler en premier ? Quelles valeurs envoyer à quelle fonction pour redimensionner la fenêtre ?

C'est là que notre ami programmeur pense à nous. Il conçoit son code de manière orientée objet. Cela signifie qu'il place tout son bazar chimique à l'intérieur d'un simple cube. Ce cube est ce qu'on appelle un objet :

Image utilisateur


Ici, une partie du cube a été volontairement mise en transparence pour vous montrer que nos fioles chimiques sont bien situées à l'intérieur du cube. Mais en réalité, le cube est complètement opaque, on ne voit rien de ce qu'il y a à l'intérieur :

Image utilisateur


Ce cube contient toutes les fonctions et les variables (nos fioles de chimie), mais il les masque à l'utilisateur.

Au lieu d'avoir des tonnes de tubes et fioles chimiques dont il faut comprendre le fonctionnement, on nous propose juste quelques boutons sur la face avant du cube : un bouton "ouvrir fenêtre", un bouton "redimensionner", etc. L'utilisateur n'a plus qu'à se servir des boutons du cube et n'a plus besoin de se soucier de tout ce qui se passe à l'intérieur. Pour l'utilisateur, c'est donc complètement simplifié.

En clair : programmer de manière orientée objet, c'est créer du code source (peut-être complexe), mais que l'on masque en le plaçant à l'intérieur d'un cube (un objet) à travers lequel on ne voit rien. Pour le programmeur qui va l'utiliser, travailler avec un objet est donc beaucoup plus simple qu'avant : il a juste à appuyer sur des boutons et n'a pas besoin d'être diplômé en chimie pour s'en servir.

Bien sûr, c'est une image, mais c'est ce qu'il faut comprendre et retenir pour le moment ;)



Nous n'allons pas voir tout de suite comment faire pour créer des objets. En revanche, nous allons apprendre à en utiliser un. Nous allons créer des objets de type string. Le type string est fourni par la librairie standard du C++.
Ce qui va suivre devrait vous convaincre une fois pour toutes que travailler avec des objets, bon sang que c'est simple :D (bon les créer sera une autre paire de manches, mais ne gâchons pas la fête qui va suivre :p ).

Lire et écrire dans une chaîne via string

Vous vous souvenez des chaînes de caractères ? Vous vous souvenez de ce chapitre un peu compliqué où je vous avais dit qu'une chaîne était un tableau de char, que toute chaîne devait se terminer par un \0, qu'il fallait bien calculer la longueur de son tableau lorsqu'on le déclarait pour ne pas oublier la place pour l'\0 ?

Ça avait donné lieu à des schémas comme celui-ci, pour expliquer par exemple la concaténation de 2 chaînes :

Image utilisateur


Bon, soyons clairs, en C++ votre ordinateur ne fonctionne pas différemment :p
C'est toujours aussi complexe à gérer (et parfois dangereux si vous omettez l'\0)... Mais si on gérait les chaînes comme des objets ? Si au lieu d'avoir tout ce bazar d'\0 et de longueurs de tableaux à gérer, on plaçait tout ça dans un gros cube (un objet) ?

Notre cube proposerait en façade plusieurs boutons pour faire toutes les opérations possibles et imaginables avec des chaînes de caractères, tout en nous évitant d'avoir à savoir comment ça fonctionne à l'intérieur.

Ce type d'objet existe, il est déjà créé et il est livré dans la librairie standard du C++. Il s'appelle string ("chaîne" en anglais).


Votre premier objet



Allez n'attendons plus, et voyons comment on crée un objet de type string dans un code source :)

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <iostream>
#include <string> // Obligatoire pour pouvoir utiliser les objets string
 
using namespace std;
 
 
int main()
{
    string maChaine; // Création d'un objet "maChaine" de type string
 
    return 0;
}


Vous remarquerez pour commencer qu'il est nécessaire d'inclure le header de la librairie string pour pouvoir utiliser des objets de type string dans le code ;) C'est ce que j'ai fait à la 2ème ligne.

Intéressons-nous maintenant à la ligne où je crée un objet de type string...

Mais... on crée un objet de la même manière qu'on crée une variable ?


Il y a plusieurs façons de créer un objet, celle que vous venez de voir est la plus simple. Et, oui, c'est exactement comme si on avait créé une variable !

Mais mais... comment on fait pour différencier les objets des variables ?


C'est bien tout le problème. Pour éviter la confusion, il y a des conventions (qu'on n'est pas obligé de suivre). La plus célèbre d'entre elles est la suivante :



Je sais ce que vous allez me dire : "string ne commence pas par une majuscule !". Il faut croire que ceux qui ont créé string ne respectaient pas cette convention. Mais rassurez-vous, maintenant la plupart des gens mettent une majuscule au début de leurs objets (dont moi), ça sera pas la foire dans la suite de ce cours ;)

Affecter une valeur à la chaîne lors de la déclaration



Pour affecter une valeur à notre objet au moment de la déclaration, il y a plusieurs possibilités. La plus courante consiste à ouvrir des parenthèses comme si on appelait une fonction :

Code : C++
1
2
3
4
5
6
int main()
{
    string maChaine("Bonjour !"); // Création d'un objet "maChaine" de type string et affectation
 
    return 0;
}


(vous commencez à comprendre ce que je vous racontais tout à l'heure quand je disais que les objets étaient une sorte de mélange de variables et fonctions ;) )

Dans la plupart des cas donc, on ouvrira des parenthèses pour affecter une valeur à l'objet lors de sa création. Pour le type string cependant, il est possible de faire encore plus simple en utilisant le symbole égal :

Code : C++
1
2
3
4
5
6
int main()
{
    string maChaine = "Bonjour !"; // Création d'un objet "maChaine" de type string et affectation
 
    return 0;
}


Bref, voilà qui est fait. On a un objet maChaine qui contient la chaîne "Bonjour !".
On peut l'afficher comme n'importe quelle chaîne de caractères avec un cout :

Code : C++
1
2
3
4
5
6
7
int main()
{
    string maChaine = "Bonjour !";
    cout << maChaine << endl; // Affichage du string comme si c'était une chaîne de caractères
 
    return 0;
}


Code : Console
Bonjour !


Affecter une valeur à la chaîne après déclaration



Maintenant que notre objet est créé, ne nous arrêtons pas là. Changeons la chaîne qui se trouve à l'intérieur. Donnez-lui la chaîne que vous voulez, il la stockera :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int main()
{
    string maChaine = "Bonjour !";
    cout << maChaine << endl;
    
    maChaine = "Bien le bonjour !";
    cout << maChaine << endl;
 
    return 0;
}


Code : Console
Bonjour !
Bien le bonjour !


Mais... on n'a pas précisé la longueur de la chaîne au début, et maintenant on stocke dedans une chaîne plus grande qu'avant ! Comment on sait s'il y aura la place de stocker une chaîne aussi longue ?


C'est là que la magie de la POO opère. Vous, l'utilisateur, vous avez appuyé sur un bouton pour dire "Je veux maintenant que la chaîne à l'intérieur change pour Bien le bonjour !". A l'intérieur de l'objet, des mécanismes (des fonctions) se sont activées lorsque vous avez fait ça. Ces fonctions ont vérifié entre autres s'il y avait de la place pour stocker la chaîne. Elles ont vu que non. Elles ont alors créé un nouveau tableau de char, suffisamment long cette fois, pour stocker la nouvelle chaîne. Et elles ont détruit l'ancien tableau qui ne servait plus à rien, tant qu'à faire.

Et permettez-moi de vous parler franchement : ce qui s'est passé à l'intérieur de l'objet, on s'en fout royalement ^^
C'est bien là tout l'intérêt de la POO : l'utilisateur n'a pas besoin de comprendre comment ça marche à l'intérieur. L'objet est en quelque sorte intelligent et gère tous les cas. Nous, on ne fait que l'utiliser ici.

Du coup, pour nous c'est simplifié comme vous avez pas idée :D
Avant, on ne pouvait pas affecter une chaîne avec le signe égal (sauf au moment de la déclaration), maintenant on peut le faire à n'importe quel moment ! Et on n'a plus à se soucier de la taille du tableau, elle est automatiquement recalculée !

Et ça, c'est rien qu'un début :p


Concaténation de chaînes



Allez, je vais continuer à vous faire baver ^^
On va concaténer (assembler) 2 chaînes. Regardez comment on fait :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int main()
{
    string chaine1 = "Bonjour !";
    string chaine2 = "Comment allez-vous ?";
    string chaine3;
 
    chaine3 = chaine1 + chaine2; // 3... 2... 1... Concaténatioooooon
    cout << chaine3 << endl;
 
    return 0;
}


Code : Console
Bonjour !Comment allez-vous ?


Ah, allez je reconnais, il manque un espace au milieu. On n'a qu'à changer la ligne de la concaténation :

Code : C++
1
chaine3 = chaine1 + " " + chaine2;


Résultat :

Code : Console
Bonjour ! Comment allez-vous ?


Niveau de simplicité : effarante :D
Avant, il aurait fallu appeler une fonction pour la concaténation, et faire attention à la longueur de la chaîne qui est modifiée pour être sûr qu'il y ait suffisamment de place dedans. Ici, rien de tout cela ^^

On assemble donc nos chaînes de caractères à l'aide du symbole +. Et avouez franchement, si vous avez un tant soit peu programmé avant, que ça va vous faire gagner un temps de fou :D


Comparaison de chaînes



Vous en voulez encore ? Très bien !
Sachez que l'on peut comparer des chaînes entre elles à l'aide des symboles == ou != (que l'on peut donc utiliser dans un if !).

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
int main()
{
    string chaine1 = "Bonjour !";
    string chaine2 = "Comment allez-vous ?";
 
    if (chaine1 == chaine2) // Faux
    {
        cout << "Les chaines sont identiques" << endl;
    }
    else
    {
        cout << "Les chaines sont differentes" << endl;
    }
 
    return 0;
}


Code : Console
Les chaines sont differentes


C'est tout bête ;)
Vous pouvez vérifier que ça marche aussi dans le cas contraire :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
int main()
{
    string chaine1 = "Bonjour !";
    string chaine2 = "Bonjour !";
 
    if (chaine1 == chaine2) // Vrai
    {
        cout << "Les chaines sont identiques" << endl;
    }
    else
    {
        cout << "Les chaines sont differentes" << endl;
    }
 
    return 0;
}


Code : Console
Les chaines sont identiques


Si ça vous amuse, testez aussi le symbole "différent de" (!=), vous verrez que 2 objets de type string sont capables de se comparer entre eux ;)



Conclusion : plus simple tu meurs :D

Opérations sur les string

Le type string ne s'arrête pas à ce que nous venons de voir. Comme tout bon objet qui se respecte, il propose un nombre important d'autres fonctionnalités qui permettent de faire tout ce dont on a besoin.

Nous n'allons pas passer toutes les fonctionnalités des string en revue (elles sont pas toutes indispensables et ce serait un peu long). Nous allons voir les principales dont vous pourriez avoir besoin dans la suite du cours :)


Attributs et méthodes



Je vous avais dit qu'un objet était constitué de variables et de fonctions. En fait, on en reparlera plus tard mais le vocabulaire est un peu différent avec les objets. Les variables contenues à l'intérieur des objets sont appelées attributs, et les fonctions sont appelées méthodes.

Imaginez que chaque méthode (fonction) que propose un objet correspond à un bouton différent sur la façade avant du cube ;)

On parle aussi de "variables membres" et de "fonctions membres", ce qui est peut-être un peu moins déroutant que "attributs" et "méthodes" qui sont des mots complètement nouveaux et auxquels on a un peu de mal à se faire au début ;)


Appeler une méthode d'un objet se fait de la même manière qu'avec les structures. On utilise le point pour séparer l'objet de sa méthode :

objet.methode()


En théorie, on peut aussi accéder aux variables membres (les "attributs") de l'objet de la même manière qu'on le faisait avec les structures. Cependant, en POO, il y a une règle super importante qui dit que l'utilisateur ne doit pas pouvoir accéder aux variables membres, mais seulement aux fonctions membres. On en reparlera dans le prochain chapitre plus en détail.


Quelques méthodes utiles du type string



La méthode size()



La méthode size() permet de connaître la longueur de la chaîne actuellement stockée dans l'objet de type string. C'est un peu l'équivalent de strlen(), mais pour les string cette fois :)

Cette méthode ne prend aucun paramètre et renvoie la longueur de la chaîne. Comme vous venez de le découvrir, il va falloir appeler la méthode de la manière suivante :

Code : C++
1
maChaine.size()


Essayons ça dans un code complet qui affiche la longueur de la chaîne :

Code : C++
1
2
3
4
5
6
7
int main()
{
    string maChaine = "Bonjour !";
    cout << "Longueur de la chaine : " << maChaine.size();
 
    return 0;
}


Code : Console
Longueur de la chaine : 9


Bingo ! :)
C'est là toute la subtilité. Avant on aurait dû faire :

Code : C
1
strlen(maChaine)


La fonction strlen était valable pour n'importe quelle chaîne, mais il fallait préciser en paramètre à chaque fois quelle était la chaîne sur laquelle la fonction devait travailler.

Maintenant, l'ordre est un peu inversé. La fonction size() est contenue dans l'objet maChaine. Quand on l'appelle comme on vient de le faire, la fonction membre size() sait qu'elle doit calculer la longueur de la chaîne contenue dans l'objet où elle se trouve :

Code : C++
1
maChaine.size()


La fonction size() est donc propre à l'objet maChaine. Si vous créez un deuxième objet de type string, il y aura donc une autre fonction size() propre à cet autre objet.

Rassurez-vous, les compilateurs C++ sont suffisamment intelligents pour optimiser l'utilisation de la mémoire. Si vous créez 50 string, il n'y aura pas 50 fois la même fonction en mémoire (une seule suffit). Mais ce que je vous dis là, c'est ce qu'il faut "imaginer". Dans chaque objet (chaque boîte), il y a une fonction size() qui est propre à l'objet. C'est comme cela qu'il faut le voir.


La méthode erase()



Cette méthode très simple supprime tout le contenu de la chaîne :

Code : C++
1
2
3
4
5
6
7
8
int main()
{
    string chaine = "Bonjour !";
    chaine.erase();
    cout << "La chaine contient : " << chaine << endl;
 
    return 0;
}


Code : Console
La chaine contient :


Comme on pouvait s'y attendre, la chaîne ne contient plus rien ;)

Notez que c'est équivalent à faire :

Code : C++
1
chaine = "";


La méthode substr()



Une autre méthode qui peut s'avérer utile : substr(). Elle permet de ne prendre qu'une partie de la chaîne stockée dans un string.

substr signifie "substring", soit "sous-chaîne" en anglais.


Tenez, on va regarder son prototype, vous allez voir que c'est intéressant :

Code : C++
1
string substr( size_type index, size_type num = npos );


Cette méthode retourne donc un objet de type string. Ce sera la sous-chaîne après "découpage".
Elle prend 2 paramètres, ou plus exactement : 1 paramètre obligatoire, 1 paramètre facultatif. En effet, num possède une valeur par défaut (npos) ce qui fait que le second paramètre ne doit pas obligatoirement être renseigné.



Allez, un exemple sera plus parlant je crois :)

Code : C++
1
2
3
4
5
6
7
int main()
{
    string chaine = "Bonjour !";
    cout << chaine.substr(3) << endl;
 
    return 0;
}


Code : Console
jour !


On a demandé à couper à partir du 3ème caractère (soit la lettre "j" vu que la première lettre correspond au caractère n°0).
On a volontairement omis le second paramètre facultatif, ce qui fait que du coup substr() a renvoyé tous les caractères restants avant la fin de la chaîne. Essayons de renseigner le paramètre facultatif pour ne pas prendre le point d'exclamation par exemple :

Code : C++
1
2
3
4
5
6
7
int main()
{
    string chaine = "Bonjour !";
    cout << chaine.substr(3, 4) << endl;
 
    return 0;
}


Code : Console
jour


Bingo ! :)
On a demandé à prendre 4 caractères en partant du caractère n°3, ce qui fait qu'on a récupéré "jour" :)


La méthode c_str()



Celle-là est un peu particulière, mais parfois fort utile. Son rôle ? Retourner un pointeur vers le tableau de char que contient l'objet de type string.

Quel intérêt me direz-vous ? En C++, à priori aucun intérêt.
Mais il peut (j'ai bien dit il "peut") arriver que vous deviez envoyer à une fonction un tableau de char classique, façon C. Dans ce cas, la méthode c_str() vous permet de récupérer un bon vieux tableau de char comme on faisait en C.

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int main()
{
    string chaine = "Bonjour !";
    const char* chaineC = NULL;
 
    chaineC = chaine.c_str(); // On récupère le tableau de char dans chaineC
    cout << "La chaine contient : " << chaineC << endl; // On l'affiche pour vérifier que ça fonctionne
 
    return 0;
}


Récupérer le tableau de char vous sera utile si vous devez envoyer une chaîne à une fonction à la base prévue pour le C qui ne reconnaît pas les string. C'est rare, mais ça arrive. Je préfère que vous sachiez qu'on a cette possibilité pour pas que vous soyez bêtement bloqué à un moment.

Autant que possible, utilisez des objets de type string plutôt que des tableaux de char : vous avez vu que c'était bien plus facile à utiliser ;)

Q.C.M.

Qu'est-ce qu'une méthode ?
Laquelle de ces déclarations d'un objet de type string est incorrecte ?
Que vaudra maChaine après ces opérations ?


Code : C++
1
2
3
string maChaine;
maChaine = "Ne criez pas";
maChaine += "si fort";
Peut-on afficher un string à l'aide d'un cout ?
Que va afficher ce code ?


Code : C++
1
2
string message("Je suis un message");
cout << message.substr(3);

Statistiques de réponses au QCM


Comme le disait si bien ma prof d'informatique "C'est plus confortable de travailler avec un string" (je vous jure que c'est vrai, j'étais là :lol: )

Bon plus sérieusement ^^
Vous avez découvert le côté utilisateur de la POO et à quel point ces nouveaux mécanismes pouvaient vous simplifier la vie.

Le côté utilisateur est en fait le côté simple de la POO. Les choses se compliquent lorsqu'on passe du côté créateur. Nous allons justement apprendre à créer des objets dans le prochain chapitre et tous les suivants. Une longue route pleine de péripéties nous attend ^^
Chapitre précédent Sommaire Chapitre suivant
Retour en haut Retour en haut


Créé : le 18/09/2007 à 17:13:58
Modifié : le 23/10/2008 à 14:17:50
Avancement : 100%
Licence : Copie non autorisée

44 commentaires

Changer de design | En savoir plus | Plan du site | Politique d'accessibilité | Règles | RSS tutoriels | RSS news
Édité par Simple IT SARL : Nous contacter | Notre blog | Revue de presse | Publicité

Y'a plus rien à lire, faut remonter maintenant !

Hébergement web - Correction de tutoriels - Créer un site
Vous souhaitez apparaître ici ? Contactez-nous.

Nombre de connectés 877 Zéros connectés | Requêtes SQL 8 requêtes | Temps de génération de la page : Total (SQL) 0.1704s (0.147s)