Plan du site  
pixel
pixel

Articles - Étudiants SUPINFO

Le C++ en bref Part.3

Par Franck MOURET Publié le 31/10/2016 à 10:55:03 Noter cet article:
(0 votes)
Avis favorable du comité de lecture

Introduction :

Dans ce chapitre, nous allons voir entre autre une notion importante en C++ et de manière général dans le monde de la programmation : les classes.

Les classes :

Les classes sont un peu comme les structures de données : comme elles, elles possèdent des membres, mais ils peuvent aussi contenir des fonctions.

Un objet est l’instanciation d'une classe. En utilisant la même réprésentation que pour une variable, la classe serait le type, et un objet serait la variable.

Les classes sont définies avec l’utilisant du mot clé class et respectent la syntaxe suivante :

Class className { }

Cette classe peut contenir des membres, des données, ou encore la déclaration de fonctions. Une classe est assez proche d’une structure(voir article part2), sauf qu’à la différence de ces dernières, une classe peut inclure des fonctions et des spécificateurs d’accès.

Les spécificateurs d'accès sont définis par un des trois mots clef suivants : private, public, protected.

Ces spécificateurs modifient les droits d'accès pour les membres qui les suivent :

- Private les membres d'une classe sont accessibles uniquement aux membres de la même classe (ou de leurs «amis» ).

- Protected les membres sont accessibles à partir d’autres membres de la même classe (ou de leurs «amis» ), à partir de membres appartenant aux classes dérivées.

- Public les membres sont accessibles partout où l'objet est visible.

Par défaut, tous les membres d'une classe déclarée avec le mot clef class sont en accès privé. Sauf si l’on le définit autrement. Par exemple :

Class Voiture {

  int vitesse ;

  public :
    void setValues(int, int) ;
};

On vient de déclarer une classe Voiture, cette classe contient deux membres. Un premier en accès privé, qui est de type int (vitesse). Comme nous n’avons pas changé son accès il est par défaut en privé. Cette classe contient aussi la définition d’une fonction que l’on a déclaré en accès public.

#include <iostream>
using namespace std;

class Voiture {

  int vitesse;

  public: void setValues (int);

  int roule() {
    return vitesse;
  }
};

void Voiture::setValues (int i) {
  vitesse = i;
}

int main () {

  Voiture voiture;
  voiture.setValues (50);
  cout << "Vitesse: " << voiture.roule();
  return 0;
}

Il existe une différence entre le nom de la classe et le nom de l’objet : dans l'exemple précédent, Voiture est le nom de la classe, alors voiture est un objet de type Voiture. Il s’agit du même genre de relation qu’entre une variable et son nom.

Pour faire la différence entre les deux, on utilise une majuscule pour la classe, alors que l’objet n’en a pas.

Une fois notre objet « voiture » créé, on peut facilement y accéder en utilisant un (.) entre le nom de notre objet et celui de notre membre. Comme nous l’avons écrit dans l’exemple :

voiture.setValues (50);

Le membre de « voiture » qui ne peut être accessible à partir de l' extérieur de la classe est vitesse, car il est en accès privé. Il ne peut donc pas être appelé à partir d'autres membres de cette même classe.

Les constructeurs :

Qu'est ce qui se passerait dans l'exemple précédent, si nous avons appelé la fonction membre roule avant d'avoir appelé setValues? Le compilateur aurait surement renvoyé un résultat comme zéro, puisque les variables n’auraient pas été initialisées.

Pour éviter cela, une classe peut inclure une fonction spéciale que l’on appelle un constructeur. Il est appelé automatiquement à chaque fois qu'un nouvel objet de cette classe est créé. Cet appel va permettre à la classe d’initialiser les variables membres ou de leur allouer un espace de stockage en mémoire.

Cette fonction « constructeur » va se déclarer comme une fonction classique, cependant, son nom doit correspondre au nom de classe et il ne doit posséder aucun type de retour, même de type void.

La classe voiture que l’on a créée peut-être améliorée en remplaçant la fonction setValue par un constructeur :

#include <iostream>

using namespace std;

class Voiture {

  private: int vitesse;
  public: Voiture (int);

  int roule() {
    return vitesse;
  }
};

Voiture::Voiture (int i) {
  vitesse = i;
}

int main () { 

  Voiture voiture (50) ;
  cout << "Vitesse: " << voiture.roule();

  return 0;
}

Le résultat de cet exemple est identique à celui de l'exemple précédent. Mais maintenant, la classe Voiture n'a plus de fonction de membre setValues, elle a un constructeur qui va effectuer une action similaire : initialiser la valeur vitesse avec les arguments qui lui sont passés.

Les arguments sont passés au constructeur au moment où l’objet de cette classe est créé :

Voiture voiture (50) ;

Un constructeur ne peut pas être appelé explicitement comme s’il était une fonction membre classique. Il n’est exécuté qu’une fois : quand un nouvel objet de cette classe est créé.

Au passage, ni la déclaration de prototype du constructeur (placée dans la classe : Voiture (int);), ni le constructeur, n’ont de valeur de retour. Pas même un void. Un constructeur ne peut jamais avoir de valeur de retour, il ne fait qu’initialiser un objet.

La surcharge de constructeurs :

Comme pour n’importe quelle autre fonction, un constructeur peut être surchargé avec différentes versions et en prenant des paramètres différents. Lors de l’exécution, le compilateur appellera automatiquement celui dont les paramètres correspondent aux arguments :

#include <iostream>

using namespace std;

class Voiture {
  private:
    int vitesse;
  public:
    Voiture ();
    Voiture (int);

  int roule() {
    return vitesse;
  }
};

Voiture::Voiture () { 
  vitesse = 90; 
}

Voiture::Voiture (int i) {
  vitesse = i;
}

int main () {
  Voiture voiture(50);
  Voiture voiture2;

  cout << "Vitesse: " << voiture.roule()<<"\n";
  cout << "Vitesse: " << voiture2.roule();

  return 0;
}

Dans l'exemple ci-dessus, deux objets de la classe Voiture sont construits : voiture et voiture2.

Mais ce qui est surtout intéressant, c’est que cet exemple introduit un constructeur spécial : le constructeur par défaut. Le constructeur par défaut est un constructeur qui ne prend aucun paramètre, et il est spécial car il est appelé quand un objet est déclaré mais il ne prend pas d’arguments. Dans l'exemple ci-dessus, le constructeur par défaut est appelé à voiture2. Du fait que le constructeur voiture prend des arguments, il ne peut donc pas être considéré comme constructeur par défaut :

Voiture voiture (50);
Voiture voiture2;

Initialisation uniforme

La façon d'appeler un constructeur en y ajoutant des arguments entre parenthèses, comme indiqué ci-dessus, est connu comme étant la forme fonctionnelle. Mais les constructeurs peuvent également être appelés avec d’autres syntaxes. Les constructeurs n’ayant qu’un seul paramètre peuvent être appelés de la manière suivante :

className objectName = initializationValue;

Plus récemment, le langage C ++ a introduit la possibilité de pouvoir appeler un constructeur en utilisant l'initialisation uniforme. Cette manière de procéder se rapproche de la forme fonctionnelle mais elle préférera utiliser des accolades ({}) plutôt que des parenthèses ( ()), ce qui nous donne le résultat suivant:

className objectName { value, value, value, ... }

Un des avantages lorsque l’on utilise cette méthode, est que, contrairement aux parenthèses, les accolades ne peuvent pas être confondues avec les déclarations de fonctions et peuvent donc être utilisées pour appeler explicitement des constructeurs par défaut:

Voiture voiture () ;
Voiture voiture {} ; 

Les pointeurs :

Un pointeur est une variable qui contient l’adresse d’une autre variable. Cette notion de programmation parait souvent complexe. Nous allons donc essayer de dé-complexifier un peu cette notion.

Pour un programme C ++, la mémoire d'un ordinateur est vue comme une succession de cellules de mémoire, ayant chacune une adresse unique. Ces adresses sont uniques et permettent à l’ordinateur de savoir où se trouve l’information qu’il cherche plus facilement. Même si ces adresses se suivent, les données qui se trouvent à l’intérieur ne se correspondent pas forcément.

La mémoire d’un ordinateur est composée de bloc de 8bits qui sont égaux à un octet. Lorsqu'une variable est déclarée, l’ordinateur va réserver en mémoire un ou plusieurs emplacements pour la stocker (par exemple une variable de type char occupera une seule case, tandis qu'une variable de type long occupera 4 cases consécutives). La taille de cette mémoire allouée va dépendre du type de données. En règle générale, les programmes ne décident pas activement des adresses mémoires où ses variables sont stockées. Cette tâche est laissée à l'environnement dans lequel le programme est exécuté (en général, c’est le système d'exploitation qui va déterminer les emplacements de mémoire à utiliser).

Pour accéder à ces variables stockées, il existe deux possibilités : En connaissant le nom de la variable comme nous le faisons, ou si l’on connait l’adresse du premier bloc mémoire attribué à notre mémoire.

Déclaration d’un pointeur :

Personne ne rentre jamais une adresse mémoire pour utiliser un pointeur, le programme va s’occuper de tout ça pour nous. L'adresse d'une variable peut être obtenue en faisant précéder le nom d'une variable avec « & » devant. Ce qui nous donne la syntaxe suivante :

type &valueName ;

#include <iostream>

using namespace std;

int main() {
  
  int i;

  cout << "L'adresse est : " << &i;

  return 0;
}

Pour déclarer un pointeur, on s’y prend de la manière suivante :

type * valueName ;

Les pointeurs peuvent tout aussi bien pointer vers une variable de type char, int, float, etc… cela n’a pas d’importance, cependant, il doit nécessairement être typé.

Le symbole « * » placé juste devant la variable permet de spécifier au compilateur que la variable qui suit est de type pointeur et pas une variable ordinaire.

Initialisation d’un pointeur :

Plus qu’une autre variable, les pointeurs doivent obligatoirement être initialisés. Un pointeur pointe vers une case mémoire dans laquelle se trouve les données qui étaient là lorsqu’on l’a déclaré. Initialiser un pointeur permet de s’assurer que la case mémoire pointée ne contient pas d’adresses utilisées par un autre programme.

L’initialisation d’un pointeur se fait quasiment de la même manière que n’importe quelle autre variable, via l’opérateur « = » et avec une variable que l’on va précéder du caractère « & ». Ce qui va donner :

PointerName = &valueName ;

#include <iostream>

using namespace std;

int main() {

  int i; 
  int * mypointer;

  mypointer = &i;
  *mypointer = 10;

  cout << "Ma valeur " << *mypointer << '\n';

  return 0;
}

Basic Input / Output

Depuis le début, nous utilisons des éléments qui nous permettent de lire et écrire des phrases ou des résultats de nos programmes. Cependant, nous n’avons pas vu tout ce qu’il est possible de faire avec ces éléments et quels sont ceux qui existent. Cette section présentera une courte introduction à certains des plus utiles.

Le langage C ++ utilise ce que l’on appel des flux pour effectuer des opérations d'entrée et de sortie dans les éléments tels que l'écran, le clavier ou un fichier. Un flux est une entité où un programme qui peut insérer ou extraire des caractères vers / depuis un média (les clavier/écrans/fichiers). Il n'y a pas besoin de connaître des détails sur les éléments associés au flux ni ses spécifications internes. Tout ce que nous devons savoir est qu’ils ont une source et une destination et qu’ils sont bien interprétées des deux cotées.

Les éléments que nous allons voir plus en détail sont : cout et cin (les flux de sortie et entrée standard) que l’on rencontre le plus souvent dans nos programmes.

La sortie standard : Cout

Dans la plupart des programmes que l’on va créer, la sortie standard par défaut est l'écran, et l'objet de flux que l’on utilise pour y accéder est cout. Ce flux de sortie associé à l’opérateur d’insertion : "<<" permet d’afficher à l’écran nos données. Au travers de ce flux, on peut afficher une phase en l’entourant de quotes :

cout << « Hello world » ;

Des entiers :

cout << 77 ;

Ou encore des variables :

cout << i ;

L’opérateur «<<» insère les données qui se trouvent après dans le flux qui le précède. Dans les exemples ci-dessus, il insère la chaîne de caractères Hello world , le nombre 77 et la valeur de la variable i dans le flux de sortie standard cout.

Lorsque le texte est enfermé entre « », le texte est imprimé littéralement, lorsqu'on les enlève, le texte est interprété comme étant l'identificateur d'une variable et sa valeur est imprimée à la place. Par exemple, ces deux phrases ont des résultats très différents :

#include <iostream>

using namespace std;

int main() {

  cout << "Hello world";
  cout << Hello world;

 return 0;
}

Ce code ne pourra pas compiler, car la deuxième instruction hello word est considérée comme une variable et le compilateur ne le trouve pas.

Il est possible d’effectuer des insertions multiples. Plusieurs (<<) peuvent être enchaînées dans une seule déclaration :

cout << "Hello" << "world" << "coco";

Ces insertions peuvent bien entendu être entrecoupées de variables.

#include <iostream>

using namespace std;

int main() {
  
  int i = 123;
  
  cout << "Hello " << "world " << i << " coco";

  return 0;
}

Ce code va insérer une variable de type int au milieu de la phrase et écrire : Hello world 123 coco. L’instruction count ne fait pas de retour à la ligne automatique. Si l’on écrit notre programme sur deux lignes avec deux instructions, ce dernier va les écrire à la suite. Par exemple, prendre les deux déclarations suivantes à insérer dans cout:

cout << "Hello ";
cout << "world";

La sortie se fait bien en une seule ligne, sans saut de ligne entre les deux :

Hello world

Pour insérer un retour à la ligne, nous allons utiliser un caractère spécial à l’endroit où l’on veut que la ligne s’arrête . En C ++, le caractère de retour à la ligne peut être spécifié comme \n.

#include <iostream>


using namespace std;

int main() {

  int i = 123;

  cout << "Hello \n";
  cout << "world";

  return 0;
}

Ce caractère doit se trouver entre le «». Ce qui nous donne la sortie suivante :

Hello

world

endl :

Cette expression est un mot clef qui signifie end line, il va donc indiquer au compilateur qu’il s’agit de la fin de notre ligne et qu’il faut aller à la suivante. Il est une alternative au « \n » que l’on vient d’utiliser. Son utilisation permet aussi d’éviter de confondre le \n avec le texte que l’on peut avoir écrit. Son utilisation est la suivante :

cout << "Hello " <<endl;

L'entrée standard : Cin

Dans la plupart des environnements de programmation, l'entrée standard par défaut est le clavier, c’est pourquoi l'objet de flux cin prends ces infos de cet endroit.

Cin est utilisé conjointement avec l'opérateur d'extraction « >> ». Cet opérateur est alors suivi par la variable depuis laquelle les données extraites sont stockées. Par exemple :

int i ;
cin >> i ;

La première instruction déclare une variable de type int appelée i, et la seconde ligne insère dans le cin la valeur de i. Si l’on met en forme ce code, lorsque le programme va arriver sur le « cin », il va se mettre en pause. En général, cela signifie que le programme attend que l'utilisateur entre une valeur avec le clavier. Dans ce cas, notez que les caractères introduits en utilisant le clavier ne sont transmis au programme que lorsque la touche ENTER est enfoncée. Tant qu’aucune valeur n’est saisie, le programme restera en attente d’une instruction pour continuer son exécution.

#include <iostream>
using namespace std;

int main() {

  int i;

  cout << "Entrez un chiffre :";
  cin >> i ;
  cout << "Vous avez saisi :" << i;
  
  return 0;
}

Comme vous pouvez le voir, extraire des informations de cin semble rendre la tâche d'obtention des données assez simple et directe. Mais cette méthode a aussi un gros inconvénient. Qu'est-ce qui se passe dans l'exemple ci-dessus, si l'utilisateur entre autre chose qui ne peut pas être interprété comme un entier ? Eh bien, dans ce cas, l'opération d'extraction échoue. Et le résultat affiché sera zéro. Ceci est le comportement d’un programme très pauvre, on ne peut pas vraiment utiliser cin tout seul, à moins de vouloir un programme qui ne serve pas à grand-chose. Si l’on veut utiliser cin, on fera attention d’ajouter des fonctions pour vérifier les informations saisies par les utilisateurs et s’assurer d’un formatage des données mieux contrôlé pour notre programme. Il est possible de récupérer plusieurs informations en une seule instruction via cin :

cin >> i >> j ;

Ceci est équivalent à:

cin >> i ;
cin >>j ;

Dans les deux cas, l'utilisateur devrait introduire deux valeurs, une pour la variable i, et une autre pour la variable j. Plusieurs types de commande sont utilisés pour séparer les deux opérations d'entrée consécutives, cela peut être soit un espace, une tabulation, ou un enter.

Cin et string

L'opérateur d'extraction cin peut être utilisée pour obtenir des chaînes de caractères de la même manière que les types de données classiques, pour cela il suffit de définir :

#include <iostream>

using namespace std;

int main() {

  string i;

  cout << "Entrez une phrase :";
  cin >> i ;
  cout << "Vous avez saisi :" << i ;

  return 0;
}

Toutefois, l'extraction avec cin considère toujours les espaces (ou tabulations, enter...) comme étant la valeur de fin d’extraction, et donc l’extraction d’une chaîne signifiera toujours : extraire un seul mot, pas une phrase ou une phrase entière.

Pour obtenir un ensemble lignes à partir cin, il existe une fonction, appelée getline, qui prend le flux ( cin) comme premier argument, et la variable de chaîne en tant que deuxième. Par exemple:

#include <iostream>
using namespace std;

int main() {

  string i;

  cout << "Entrez une phrase :";
  getline (cin, i);
  cout << "Vous avez saisi :" << i ;

  return 0;
}

L’utilisation de getline nous permet bien de récupérer plusieurs arguments de type string. Le comportement standard que la plupart des utilisateurs attendent d'un programme de type console est que chaque fois que le programme interroge l'utilisateur pour entrer des informations, l'utilisateur introduise le champ, et appuie ensuite ENTER pour valider sa saisie. C’est exactement ce que fait getline. Une fois toutes les informations saisies, l’utilisateur valide sa saisie par enter, signifiant à la fonction que la saisie est terminée.

Conclusion :

Cette série d’articles m’a permis de passer en revue certains des éléments les plus important du C++. En prenant un peu plus de temps il serait possible de voir plus en profondeur certains éléments, mais il ne s’agit pas du but de ces articles. Leur but est seulement de présenter ce langage, aider à éclaircir certains points ou donner envie d’en apprendre plus sur le C++.

Webographie :

https://fr.wikipedia.org/wiki/C%2B%2B

http://alp.developpez.com/tutoriels/debuter-cpp/

https://openclassrooms.com/courses/programmez-avec-le-langage-c/

http://www.cplusplus.com/

Livres :

Pour les nuls – C++

Editions Eyrolles – Programmer en C++

A propos de SUPINFO | Contacts & adresses | Enseigner à SUPINFO | Presse | Conditions d'utilisation & Copyright | Respect de la vie privée | Investir
Logo de la société Cisco, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société IBM, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Sun-Oracle, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Apple, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Sybase, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Novell, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Intel, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Accenture, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société SAP, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Prometric, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Toeic, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo du IT Academy Program par Microsoft, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management

SUPINFO International University
Ecole d'Informatique - IT School
École Supérieure d'Informatique de Paris, leader en France
La Grande Ecole de l'informatique, du numérique et du management
Fondée en 1965, reconnue par l'État. Titre Bac+5 certifié au niveau I.
SUPINFO International University is globally operated by EDUCINVEST Belgium - Avenue Louise, 534 - 1050 Brussels