Nous n'allons pas voir tout de suite comment faire pour créer des objets, en revanche nous allons apprendre à en utiliser un.
Comprenez d'abord le fonctionnement de string
Dans ce chapitre, nous allons nous pencher sur le cas de string
.
J'ai déjà utilisé le type string
, ce n'est pas une nouveauté pour moi ! C'est le type qui permet de stocker du texte en mémoire, c'est cela ?
Oui ! Mais le type string
est différent des autres.
Je vais vous montrer comment fonctionne string
"à l'intérieur du cube". Préparez-vous à d'horribles vérités.
Horrible vérité n° 1 : Pour un ordinateur, les lettres n'existent pas…
L'avantage des objets est de masquer la complexité du code à l'utilisateur. Et justement, les choses sont compliquées parce que, à la base, un ordinateur ne sait pas gérer du texte ! Oui, l'ordinateur n'est véritablement qu'une grosse machine à calculer dénuée de sentiments. Il ne reconnaît que des nombres.
Mais alors, si l'ordinateur ne peut manipuler que des nombres, comment se fait-il qu'il puisse afficher du texte à l'écran ?
Grâce à une astuce que l'on utilise depuis longtemps !
Nombre | Lettre | Nombre | Lettre |
---|---|---|---|
64 | @ | 96 | ' |
65 | A | 97 | a |
66 | B | 98 | b |
67 | C | 99 | c |
68 | D | 100 | d |
69 | E | 101 | e |
70 | F | 102 | f |
71 | G | 103 | g |
72 | H | 104 | h |
73 | I | 105 | i |
74 | J | 106 | j |
75 | K | 107 | k |
76 | L | 108 | l |
77 | M | 109 | m |
Comme vous le voyez :
la lettre « A » majuscule correspond au nombre ;
la lettre « a » minuscule correspond au nombre ;
etc.
Alors, à chaque fois que l'ordinateur voit le nombre , il prend cela pour la lettre A ?
Non, l'ordinateur ne traduit un nombre en lettre que si on le lui demande. En pratique, on se base sur le type de la variable pour savoir si le nombre stocké est véritablement un nombre ou, en réalité, une lettre :
Si on utilise le type
int
pour stocker le nombre , l'ordinateur considérera que c'est un nombre.En revanche, si on utilise le type
char
pour stocker le nombre , l'ordinateur se dira "C'est la lettre A".
Un char
ne peut stocker qu'un seul caractère ? Comment fait-on alors pour stocker une phrase entière ?
Eh bien, là non plus, ce n'est pas simple ! C'est un autre problème que nous allons voir...
Horrible vérité n° 2 : Les textes sont des tableaux de char
Puisque char
ne peut stocker qu'une seule lettre, les programmeurs ont eu l'idée de créer... un tableau de char
! Mais ça, vous le saviez déjà.
Ainsi, il suffit de :
déclarer un tableau de
char
pour pouvoir stocker du texte (environ 100 caractères) :
char texte[100];
ou utiliser un
vector
si on veut changer la longueur du texte :
vector<char> texte;
Le texte n'est donc en fait qu'un assemblage de lettres, stocké en mémoire dans un tableau :
T | e | x | t | e |
Chaque case correspond à un char
. Tous ces char
mis côte à côte forment du texte.
Gérer du texte n'est pas vraiment simple. Il faut :
créer un tableau de
char
dont chaque case correspond à un caractère ;prévoir une taille suffisante pour stocker le texte que l'on souhaite sinon cela plante...
Bref, cela fait beaucoup de choses auxquelles il faut penser.
C'est là qu'intervient la programmation orientée objet : un développeur place le tout dans un cube facile à utiliser où il suffit d'appuyer sur des boutons. Ce cube, c'est l'objet string
.
Créez un objet string
Vous le savez déjà, la création d'un objet ressemble beaucoup à la création d'une variable classique comme int
ou double
:
#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;
}
Pour pouvoir utiliser des objets de type string
dans le code, il est nécessaire d'inclure l'en-tête de la bibliothèque string
. C'est ce que j'ai fait à la deuxième ligne.
Intéressons-nous maintenant à la ligne où je crée un objet de type string
...
Donc... 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... comment on fait pour différencier les objets des variables ?
C'est bien tout le problème : variables et objets se ressemblent dans le code. Pour éviter la confusion, il y a des conventions. La plus célèbre d'entre elles est la suivante :
le type des variables commence par une minuscule (ex. : int) ;
le type des objets commence par une majuscule (ex. : Voiture).
Je sais ce que vous allez me dire :
string
ne commence pas par une majuscule alors que c'est un objet !
Initialisez la chaîne lors de la déclaration
Pour initialiser notre objet au moment de la déclaration (et donc lui donner une valeur), il y a plusieurs possibilités.
La plus courante consiste à ouvrir des parenthèses comme nous l'avons fait jusqu'ici :
int main()
{
string maChaine("Bonjour !");
//Création d'un objet 'maChaine' de type string et initialisation
return 0;
}
C'est la technique classique que l'on connaît déjà, et qui s'applique aussi bien aux variables qu'aux objets. On dit que l'on construit l'objet.
On a maintenant créé 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
:
int main()
{
string maChaine("Bonjour !");
cout << maChaine << endl;
//Affichage du string comme si c'était une chaîne de caractères
return 0;
}
Bonjour !
Affectez une valeur à la chaîne après déclaration
Maintenant que notre objet est créé, ne nous arrêtons pas là. Changeons le contenu de la chaîne après sa déclaration :
int main()
{
string maChaine("Bonjour !");
cout << maChaine << endl;
maChaine = "Bien le bonjour !";
cout << maChaine << endl;
return 0;
}
Bonjour ! Bien le bonjour !
Tout cela, vous savez déjà le faire. Ce que je veux vous montrer ici, c'est comment 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 devienne "Bien le bonjour !".
À l'intérieur de l'objet, des mécanismes (des fonctions) se sont activés lorsque vous avez réalisé l'opération. Ces fonctions ont vérifié, entre autres, s'il y avait de la place pour stocker la chaîne dans le tableau de
char
.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, tant qu'à faire, elles ont détruit l'ancien tableau qui ne servait plus à rien, puis les nouvelles lettres ont été copiées.
Mais permettez-moi de vous parler franchement : ce qui s'est passé à l'intérieur de l'objet, on s'en fiche royalement ! C'est bien là tout l'intérêt de la POO : l'utilisateur n'a pas besoin de comprendre comment cela fonctionne à l'intérieur. On se moque de savoir que le texte est stocké dans un tableau de char
(ou est-ce un vector
?). L'objet est en quelque sorte intelligent et gère tous les cas. Nous, nous nous contentons de l'utiliser.
Assemblez des chaînes de caractères
Imaginez que l'on souhaite concaténer (assembler) deux chaînes. En théorie, c'est compliqué à faire car il faut fusionner deux tableaux de char
. En pratique, la POO nous évite de nous soucier du fonctionnement interne :
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;
}
Bonjour !Comment allez-vous ?
À L'affichage, il manque une espace au milieu. On n'a qu'à changer la ligne de la concaténation :
chaine3 = chaine1 + " " + chaine2;
Résultat :
Bonjour ! Comment allez-vous ?
C'est très simple à utiliser alors que "derrière", ça s'active pour assembler les deux tableaux dechar
.
Comparez des chaînes de caractères
On peut comparer des chaînes entre elles à l'aide des symboles ==
(identique) ou !=
(différent) dans un if
:
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;
}
Les chaines sont differentes.
À l'intérieur de l'objet, la comparaison se fait caractère par caractère entre les deux tableaux de char
(à l'aide d'une boucle qui compare chacune des lettres). Nous, nous n'avons pas à nous soucier de tout cela : nous demandons à l'objet chaine1
s'il est identique à chaine2
; il fait des calculs et nous répond très simplement par un oui ou un non.
Dans la suite du cours, nous allons apprendre comment faire pour écrire de tels objets, où toutes les opérations complexes sont cachées. Vous pourrez alors utiliser ces boîtes dans d'autres parties de votre programme, sans avoir à vous soucier ni même à vous rappeler de leur fonctionnement.
Faites des opérations sur les string
Comme tout objet qui se respecte, le type string
propose un nombre important d'autres fonctionnalités qui permettent de faire tout ce dont on a besoin. Voyons les principales.
Retenez le vocabulaire de base en POO : "Attribut" et "méthode"
Imaginez que chaque méthode (fonction) que propose un objet corresponde à un bouton différent sur la face avant du cube. Pour appeler la méthode d'un objet, on utilise une écriture que vous avez déjà vue : objet.methode()
. On sépare le nom de l'objet et le nom de la méthode par un point.
Cela signifie :
"Sur l'objet indiqué, j'appelle cette méthode".
Traduction : "Sur le cube indiqué, j'appuie sur ce bouton pour déclencher une action".
Utilisez les méthodes du type string
La méthode size()
Vous le savez déjà, la méthode size()
permet de connaître la longueur de la chaîne actuellement stockée dans l'objet de type string
.
Cette méthode ne prend aucun paramètre et renvoie la longueur de la chaîne. Vous venez de découvrir qu'il s'agit d'une règle générale, mais nous l'avions déjà fait avant ; il faut appeler la méthode de la manière suivante :
maChaine.size()
Essayons cela dans un code complet qui affiche la longueur d'une chaîne de caractères :
int main()
{
string maChaine("Bonjour !");
cout << "Longueur de la chaine : " << maChaine.size();
return 0;
}
Longueur de la chaine : 9
La méthode erase()
Cette méthode très simple supprime tout le contenu de la chaîne :
int main()
{
string chaine("Bonjour !");
chaine.erase();
cout << "La chaine contient : " << chaine << endl;
return 0;
}
La chaine contient :
Comme on pouvait s'y attendre, la chaîne ne contient plus rien.
La méthode substr()
Cette méthode permet d'extraire une partie de la chaîne stockée dans une string
.
Tenez, on va regarder son prototype, vous allez voir que c'est intéressant :
string substr( size_type index, size_type num = npos );
Cette méthode renvoie donc un objet de type string
.
Ce sera la sous-chaîne obtenue après découpage.
Elle prend deux paramètres ou, plus exactement, un paramètre obligatoire et un 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é.
Voyons plus en détail ce qui se cache sous ces paramètres :
index
permet d'indiquer à partir de quel caractère on doit couper (ce doit être un numéro de caractère).num
permet d'indiquer le nombre de caractères que l'on prend. Par défaut, la valeur estnpos
, ce qui revient à prendre tous les caractères qui restent. Si vous indiquez 2, la méthode ne renverra que 2 caractères.
Allez, un exemple sera plus parlant, je crois :
int main()
{
string chaine("Bonjour !");
cout << chaine.substr(3) << endl;
return 0;
}
jour !
On a demandé à couper à partir du troisième caractère, soit la lettre "j" (étant donné que la première lettre correspond au caractère n° 0).
On a volontairement omis le second paramètre facultatif, ce qui fait que substr()
a renvoyé tous les caractères restants jusqu'à la fin de la chaîne.
Essayons de renseigner le paramètre facultatif pour exclure le point d'exclamation, par exemple :
int main()
{
string chaine("Bonjour !");
cout << chaine.substr(3, 4) << endl;
return 0;
}
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".
string chaine("Bonjour !");
cout << chaine[3] << endl; //Affiche la lettre 'j'
En résumé
La programmation orientée objet est une façon de concevoir son code. On considère qu'on manipule des objets.
Les objets sont parfois complexes à l'intérieur, mais leur utilisation nous est volontairement simplifiée. C'est un des avantages de la programmation orientée objet.
Un objet est constitué d'attributs et de méthodes, c'est-à-dire de variables et de fonctions membres.
On appelle les méthodes de ces objets pour les modifier ou obtenir des informations.
La gestion du texte en mémoire est en fait complexe. Pour nous simplifier les choses, le langage C++ nous propose le type
string
. Grâce à lui, nous pouvons créer des objets de typestring
et manipuler du texte sans avoir à nous soucier du fonctionnement de la mémoire.
Vous venez de découvrir le monde de la programmation orientée objet, et je pense que tout n’est pas encore clair pour vous. Nous allons sans tarder créer votre première classe, rien de mieux que de pratiquer pour comprendre. Vous êtes prêt ?