Guide rapide C ++

C ++ est un langage de programmation de forme libre, de type statique, compilé, polyvalent, sensible à la casse, qui prend en charge la programmation procédurale, orientée objet et générique.

C ++ est considéré comme un middle-level langue, car elle comprend une combinaison de fonctionnalités linguistiques de haut niveau et de bas niveau.

C ++ a été développé par Bjarne Stroustrup à partir de 1979 chez Bell Labs à Murray Hill, New Jersey, comme une amélioration du langage C et s'appelait à l'origine C with Classes, mais plus tard, il a été renommé C ++ en 1983.

C ++ est un sur-ensemble de C et que pratiquement tout programme C légal est un programme C ++ légal.

Note - On dit qu'un langage de programmation utilise le typage statique lorsque la vérification de type est effectuée au moment de la compilation par opposition à l'exécution.

Programmation orientée objet

C ++ prend entièrement en charge la programmation orientée objet, y compris les quatre piliers du développement orienté objet -

  • Encapsulation
  • Masquage des données
  • Inheritance
  • Polymorphism

Bibliothèques standard

Le C ++ standard se compose de trois parties importantes -

  • Le langage de base donnant tous les blocs de construction, y compris les variables, les types de données et les littéraux, etc.

  • La bibliothèque standard C ++ offrant un riche ensemble de fonctions manipulant des fichiers, des chaînes, etc.

  • La bibliothèque de modèles standard (STL) donnant un riche ensemble de méthodes manipulant les structures de données, etc.

La norme ANSI

La norme ANSI est une tentative de garantir que C ++ est portable; ce code que vous écrivez pour le compilateur de Microsoft se compilera sans erreur, en utilisant un compilateur sur un Mac, UNIX, une boîte Windows ou un Alpha.

La norme ANSI est stable depuis un certain temps et tous les principaux fabricants de compilateurs C ++ prennent en charge la norme ANSI.

Apprendre le C ++

La chose la plus importante lors de l'apprentissage du C ++ est de se concentrer sur les concepts.

Le but de l'apprentissage d'un langage de programmation est de devenir un meilleur programmeur; c'est-à-dire devenir plus efficace dans la conception et la mise en œuvre de nouveaux systèmes et dans la maintenance des anciens.

C ++ prend en charge une variété de styles de programmation. Vous pouvez écrire dans le style Fortran, C, Smalltalk, etc., dans n'importe quelle langue. Chaque style peut atteindre ses objectifs de manière efficace tout en préservant la durée d'exécution et l'efficacité de l'espace.

Utilisation de C ++

C ++ est utilisé par des centaines de milliers de programmeurs dans pratiquement tous les domaines d'application.

C ++ est très utilisé pour écrire des pilotes de périphériques et d'autres logiciels qui reposent sur la manipulation directe du matériel sous des contraintes en temps réel.

Le C ++ est largement utilisé pour l'enseignement et la recherche car il est suffisamment propre pour un enseignement réussi des concepts de base.

Quiconque a utilisé un Apple Macintosh ou un PC exécutant Windows a indirectement utilisé C ++ car les principales interfaces utilisateur de ces systèmes sont écrites en C ++.

Configuration de l'environnement local

Si vous souhaitez toujours configurer votre environnement pour C ++, vous devez disposer des deux logiciels suivants sur votre ordinateur.

Éditeur de texte

Cela sera utilisé pour taper votre programme. Quelques exemples d'éditeurs incluent le Bloc-notes Windows, la commande d'édition du système d'exploitation, Brief, Epsilon, EMACS et vim ou vi.

Le nom et la version de l'éditeur de texte peuvent varier selon les systèmes d'exploitation. Par exemple, le Bloc-notes sera utilisé sous Windows et vim ou vi peut être utilisé sur Windows ainsi que Linux ou UNIX.

Les fichiers que vous créez avec votre éditeur sont appelés fichiers source et pour C ++, ils sont généralement nommés avec l'extension .cpp, .cp ou .c.

Un éditeur de texte doit être en place pour démarrer votre programmation C ++.

Compilateur C ++

Il s'agit d'un véritable compilateur C ++, qui sera utilisé pour compiler votre code source en programme exécutable final.

La plupart des compilateurs C ++ ne se soucient pas de l'extension que vous donnez à votre code source, mais si vous ne spécifiez pas le contraire, beaucoup utiliseront .cpp par défaut.

Le compilateur le plus fréquemment utilisé et disponible gratuitement est le compilateur GNU C / C ++, sinon vous pouvez avoir des compilateurs de HP ou de Solaris si vous avez les systèmes d'exploitation respectifs.

Installation du compilateur GNU C / C ++

Installation UNIX / Linux

Si vous utilisez Linux or UNIX puis vérifiez si GCC est installé sur votre système en entrant la commande suivante à partir de la ligne de commande -

$ g++ -v

Si vous avez installé GCC, il devrait afficher un message tel que le suivant -

Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr .......
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)

Si GCC n'est pas installé, vous devrez l'installer vous-même en suivant les instructions détaillées disponibles sur https://gcc.gnu.org/install/

Installation sous Mac OS X

Si vous utilisez Mac OS X, le moyen le plus simple d'obtenir GCC est de télécharger l'environnement de développement Xcode à partir du site Web d'Apple et de suivre les instructions d'installation simples.

Xcode est actuellement disponible sur developer.apple.com/technologies/tools/ .

Installation de Windows

Pour installer GCC sous Windows, vous devez installer MinGW. Pour installer MinGW, allez sur la page d'accueil de MinGW, www.mingw.org , et suivez le lien vers la page de téléchargement de MinGW. Téléchargez la dernière version du programme d'installation MinGW qui doit être nommé MinGW- <version> .exe.

Lors de l'installation de MinGW, au minimum, vous devez installer gcc-core, gcc-g ++, binutils et le runtime MinGW, mais vous souhaiterez peut-être en installer d'autres.

Ajoutez le sous-répertoire bin de votre installation MinGW à votre PATH variable d'environnement afin que vous puissiez spécifier ces outils sur la ligne de commande par leurs noms simples.

Une fois l'installation terminée, vous pourrez exécuter gcc, g ++, ar, ranlib, dlltool et plusieurs autres outils GNU à partir de la ligne de commande Windows.

Lorsque nous considérons un programme C ++, il peut être défini comme une collection d'objets qui communiquent en invoquant les méthodes de chacun. Voyons maintenant brièvement ce que signifient une classe, un objet, des méthodes et des variables instantanées.

  • Object- Les objets ont des états et des comportements. Exemple: un chien a des états - couleur, nom, race ainsi que comportements - remuer, aboyer, manger. Un objet est une instance d'une classe.

  • Class - Une classe peut être définie comme un modèle / plan qui décrit les comportements / états pris en charge par l'objet de son type.

  • Methods- Une méthode est essentiellement un comportement. Une classe peut contenir de nombreuses méthodes. C'est dans les méthodes que les logiques sont écrites, les données sont manipulées et toutes les actions sont exécutées.

  • Instance Variables- Chaque objet a son ensemble unique de variables d'instance. L'état d'un objet est créé par les valeurs affectées à ces variables d'instance.

Structure du programme C ++

Regardons un code simple qui imprimerait les mots Hello World .

#include <iostream>
using namespace std;

// main() is where program execution begins.
int main() {
   cout << "Hello World"; // prints Hello World
   return 0;
}

Regardons les différentes parties du programme ci-dessus -

  • Le langage C ++ définit plusieurs en-têtes, qui contiennent des informations nécessaires ou utiles à votre programme. Pour ce programme, l'en-tête<iostream> est nécessaire.

  • La ligne using namespace std;indique au compilateur d'utiliser l'espace de noms std. Les espaces de noms sont un ajout relativement récent à C ++.

  • La ligne suivante '// main() is where program execution begins.'est un commentaire sur une seule ligne disponible en C ++. Les commentaires sur une seule ligne commencent par // et s'arrêtent à la fin de la ligne.

  • La ligne int main() est la fonction principale où commence l'exécution du programme.

  • La ligne suivante cout << "Hello World"; provoque l'affichage du message «Hello World» à l'écran.

  • La ligne suivante return 0; termine la fonction main () et la force à renvoyer la valeur 0 au processus appelant.

Compiler et exécuter un programme C ++

Voyons comment enregistrer le fichier, compiler et exécuter le programme. Veuillez suivre les étapes ci-dessous -

  • Ouvrez un éditeur de texte et ajoutez le code comme ci-dessus.

  • Enregistrez le fichier sous: hello.cpp

  • Ouvrez une invite de commande et accédez au répertoire dans lequel vous avez enregistré le fichier.

  • Tapez 'g ++ hello.cpp' et appuyez sur Entrée pour compiler votre code. S'il n'y a pas d'erreur dans votre code, l'invite de commande vous amènera à la ligne suivante et générera un fichier exécutable.

  • Maintenant, tapez «a.out» pour exécuter votre programme.

  • Vous pourrez voir «Hello World» imprimé sur la fenêtre.

$ g++ hello.cpp
$ ./a.out
Hello World

Assurez-vous que g ++ est dans votre chemin et que vous l'exécutez dans le répertoire contenant le fichier hello.cpp.

Vous pouvez compiler des programmes C / C ++ en utilisant makefile. Pour plus de détails, vous pouvez consulter notre «Tutoriel Makefile» .

Points-virgules et blocs en C ++

En C ++, le point-virgule est un terminateur d'instruction. Autrement dit, chaque instruction individuelle doit se terminer par un point-virgule. Il indique la fin d'une entité logique.

Par exemple, voici trois déclarations différentes -

x = y;
y = y + 1;
add(x, y);

Un bloc est un ensemble d'instructions connectées logiquement qui sont entourées d'accolades ouvrantes et fermantes. Par exemple -

{
   cout << "Hello World"; // prints Hello World
   return 0;
}

C ++ ne reconnaît pas la fin de la ligne comme un terminateur. Pour cette raison, peu importe où vous mettez une instruction dans une ligne. Par exemple -

x = y;
y = y + 1;
add(x, y);

est le même que

x = y; y = y + 1; add(x, y);

Identificateurs C ++

Un identificateur C ++ est un nom utilisé pour identifier une variable, une fonction, une classe, un module ou tout autre élément défini par l'utilisateur. Un identificateur commence par une lettre A à Z ou a à z ou un trait de soulignement (_) suivi de zéro ou plusieurs lettres, traits de soulignement et chiffres (0 à 9).

C ++ n'autorise pas les caractères de ponctuation tels que @, $ et% dans les identificateurs. C ++ est un langage de programmation sensible à la casse. Donc,Manpower et manpower sont deux identificateurs différents en C ++.

Voici quelques exemples d'identifiants acceptables -

mohd       zara    abc   move_name  a_123
myname50   _temp   j     a23b9      retVal

Mots clés C ++

La liste suivante montre les mots réservés en C ++. Ces mots réservés ne peuvent pas être utilisés comme constantes ou variables ou tout autre nom d'identifiant.

asm autre Nouveau ce
auto énumération opérateur jeter
booléen explicite privé vrai
Pause exportation protégé essayer
Cas externe Publique typedef
capture faux S'inscrire typeid
carboniser flotte réinterpréter_cast nom de type
classe pour revenir syndicat
const ami court non signé
const_cast aller à signé en utilisant
continuer si taille de virtuel
défaut en ligne statique néant
effacer int static_cast volatil
faire longue struct wchar_t
double mutable commutateur tandis que
dynamic_cast espace de noms modèle  

Trigraphes

Quelques caractères ont une représentation alternative, appelée séquence trigraphique. Un trigraphe est une séquence de trois caractères qui représente un seul caractère et la séquence commence toujours par deux points d'interrogation.

Les trigraphes sont développées partout où elles apparaissent, y compris dans les littéraux de chaîne et de caractères, dans les commentaires et dans les directives de préprocesseur.

Voici les séquences de trigraphes les plus fréquemment utilisées -

Trigraphe Remplacement
?? = #
?? / \
?? ' ^
?? ( [
??) ]
??! |
?? < {
??> }
?? - ~

Tous les compilateurs ne prennent pas en charge les trigraphes et il n'est pas conseillé de les utiliser en raison de leur nature déroutante.

Espace blanc en C ++

Une ligne ne contenant que des espaces, éventuellement avec un commentaire, est appelée ligne vide et le compilateur C ++ l'ignore totalement.

L'espace blanc est le terme utilisé en C ++ pour décrire les espaces, les tabulations, les caractères de nouvelle ligne et les commentaires. L'espace blanc sépare une partie d'une instruction d'une autre et permet au compilateur d'identifier où un élément dans une instruction, comme int, se termine et où commence l'élément suivant.

Énoncé 1

int age;

Dans l'instruction ci-dessus, il doit y avoir au moins un caractère d'espacement (généralement un espace) entre int et age pour que le compilateur puisse les distinguer.

Énoncé 2

fruit = apples + oranges;   // Get the total fruit

Dans la déclaration 2 ci-dessus, aucun espace n'est nécessaire entre les fruits et =, ou entre = et les pommes, bien que vous soyez libre d'en inclure si vous souhaitez des raisons de lisibilité.

Les commentaires de programme sont des instructions explicatives que vous pouvez inclure dans le code C ++. Ces commentaires aident quiconque lit le code source. Tous les langages de programmation autorisent une certaine forme de commentaires.

C ++ prend en charge les commentaires sur une seule ligne et sur plusieurs lignes. Tous les caractères disponibles dans tout commentaire sont ignorés par le compilateur C ++.

Les commentaires C ++ commencent par / * et se terminent par * /. Par exemple -

/* This is a comment */

/* C++ comments can also
   * span multiple lines
*/

Un commentaire peut également commencer par //, s'étendant jusqu'à la fin de la ligne. Par exemple -

#include <iostream>
using namespace std;

main() {
   cout << "Hello World"; // prints Hello World
   
   return 0;
}

Lorsque le code ci-dessus est compilé, il ignorera // prints Hello World et l'exécutable final produira le résultat suivant -

Hello World

Dans un commentaire / * et * /, // les caractères n'ont pas de signification particulière. Dans un // commentaire, / * et * / n'ont pas de signification particulière. Ainsi, vous pouvez "imbriquer" un type de commentaire dans un autre type. Par exemple -

/* Comment out printing of Hello World:

cout << "Hello World"; // prints Hello World

*/

Lors de l'écriture d'un programme dans n'importe quelle langue, vous devez utiliser diverses variables pour stocker diverses informations. Les variables ne sont rien d'autre que des emplacements de mémoire réservés pour stocker des valeurs. Cela signifie que lorsque vous créez une variable, vous réservez de l'espace en mémoire.

Vous pouvez souhaiter stocker des informations de différents types de données comme des caractères, des caractères larges, des entiers, des virgule flottante, des virgules flottantes doubles, des booléens, etc. mémoire réservée.

Types intégrés primitifs

C ++ offre au programmeur un riche assortiment de types de données intégrés et définis par l'utilisateur. Le tableau suivant répertorie sept types de données de base C ++ -

Type Mot-clé
Booléen booléen
Personnage carboniser
Entier int
Point flottant flotte
Double virgule flottante double
Sans valeur néant
Caractère large wchar_t

Plusieurs des types de base peuvent être modifiés en utilisant un ou plusieurs de ces modificateurs de type -

  • signed
  • unsigned
  • short
  • long

Le tableau suivant montre le type de variable, la quantité de mémoire nécessaire pour stocker la valeur en mémoire et les valeurs maximale et minimale pouvant être stockées dans ce type de variables.

Type Largeur de bit typique Gamme typique
carboniser 1 octet -127 à 127 ou 0 à 255
caractère non signé 1 octet 0 à 255
char signé 1 octet -127 à 127
int 4 octets -2147483648 à 2147483647
int non signé 4 octets 0 à 4294967295
signé int 4 octets -2147483648 à 2147483647
int court 2 octets -32768 à 32767
int court non signé 2 octets 0 à 65 535
signé court int 2 octets -32768 à 32767
long int 8 octets -2 147 483 648 à 2 147 483 647
signé long int 8 octets idem long int
entier long non signé 8 octets 0 à 4 294 967 295
long long int 8 octets - (2 ^ 63) à (2 ^ 63) -1
unsigned long long int 8 octets 0 à 18,446,744,073,709,551,615
flotte 4 octets
double 8 octets
long double 12 octets
wchar_t 2 ou 4 octets 1 caractère large

La taille des variables peut être différente de celles indiquées dans le tableau ci-dessus, selon le compilateur et l'ordinateur que vous utilisez.

Voici l'exemple qui produira la taille correcte de divers types de données sur votre ordinateur.

#include <iostream>
using namespace std;

int main() {
   cout << "Size of char : " << sizeof(char) << endl;
   cout << "Size of int : " << sizeof(int) << endl;
   cout << "Size of short int : " << sizeof(short int) << endl;
   cout << "Size of long int : " << sizeof(long int) << endl;
   cout << "Size of float : " << sizeof(float) << endl;
   cout << "Size of double : " << sizeof(double) << endl;
   cout << "Size of wchar_t : " << sizeof(wchar_t) << endl;
   
   return 0;
}

Cet exemple utilise endl, qui insère un caractère de nouvelle ligne après chaque ligne et l'opérateur << est utilisé pour transmettre plusieurs valeurs à l'écran. Nous utilisons égalementsizeof() opérateur pour obtenir la taille de divers types de données.

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant qui peut varier d'une machine à l'autre -

Size of char : 1
Size of int : 4
Size of short int : 2
Size of long int : 4
Size of float : 4
Size of double : 8
Size of wchar_t : 4

Déclarations typedef

Vous pouvez créer un nouveau nom pour un type existant en utilisant typedef. Voici la syntaxe simple pour définir un nouveau type à l'aide de typedef -

typedef type newname;

Par exemple, ce qui suit indique au compilateur que feet est un autre nom pour int -

typedef int feet;

Maintenant, la déclaration suivante est parfaitement légale et crée une variable entière appelée distance -

feet distance;

Types énumérés

Un type énuméré déclare un nom de type facultatif et un ensemble de zéro ou plusieurs identificateurs qui peuvent être utilisés comme valeurs du type. Chaque énumérateur est une constante dont le type est l'énumération.

La création d'une énumération nécessite l'utilisation du mot-clé enum. La forme générale d'un type d'énumération est -

enum enum-name { list of names } var-list;

Ici, le nom-enum est le nom du type de l'énumération. La liste des noms est séparée par des virgules.

Par exemple, le code suivant définit une énumération de couleurs appelées colors et la variable c de type color. Enfin, c reçoit la valeur "bleu".

enum color { red, green, blue } c;
c = blue;

Par défaut, la valeur du premier nom est 0, le deuxième nom a la valeur 1 et le troisième a la valeur 2, et ainsi de suite. Mais vous pouvez donner un nom, une valeur spécifique en ajoutant un initialiseur. Par exemple, dans l'énumération suivante,green aura la valeur 5.

enum color { red, green = 5, blue };

Ici, blue aura une valeur de 6 car chaque nom sera un plus grand que celui qui le précède.

Une variable nous fournit un stockage nommé que nos programmes peuvent manipuler. Chaque variable en C ++ a un type spécifique, qui détermine la taille et la disposition de la mémoire de la variable; la plage de valeurs pouvant être stockées dans cette mémoire; et l'ensemble des opérations qui peuvent être appliquées à la variable.

Le nom d'une variable peut être composé de lettres, de chiffres et du caractère de soulignement. Il doit commencer par une lettre ou un trait de soulignement. Les lettres majuscules et minuscules sont distinctes car C ++ est sensible à la casse -

Il existe les types de variables de base suivants en C ++, comme expliqué dans le dernier chapitre -

Sr.Non Type et description
1

bool

Stocke la valeur true ou false.

2

char

Généralement un seul octet (un octet). Il s'agit d'un type entier.

3

int

La taille entière la plus naturelle de la machine.

4

float

Valeur à virgule flottante simple précision.

5

double

Une valeur à virgule flottante double précision.

6

void

Représente l'absence de type.

sept

wchar_t

Un type de caractère large.

C ++ permet également de définir divers autres types de variables, que nous aborderons dans les chapitres suivants comme Enumeration, Pointer, Array, Reference, Data structures, et Classes.

La section suivante couvrira comment définir, déclarer et utiliser différents types de variables.

Définition de variable en C ++

Une définition de variable indique au compilateur où et combien de stockage créer pour la variable. Une définition de variable spécifie un type de données et contient une liste d'une ou plusieurs variables de ce type comme suit -

type variable_list;

Ici, type doit être un type de données C ++ valide, y compris char, w_char, int, float, double, bool ou tout objet défini par l'utilisateur, etc., et variable_listpeut consister en un ou plusieurs noms d'identifiants séparés par des virgules. Certaines déclarations valides sont affichées ici -

int    i, j, k;
char   c, ch;
float  f, salary;
double d;

La ligne int i, j, k;à la fois déclare et définit les variables i, j et k; qui demande au compilateur de créer des variables nommées i, j et k de type int.

Les variables peuvent être initialisées (affectées d'une valeur initiale) dans leur déclaration. L'initialiseur se compose d'un signe égal suivi d'une expression constante comme suit -

type variable_name = value;

Quelques exemples sont -

extern int d = 3, f = 5;    // declaration of d and f. 
int d = 3, f = 5;           // definition and initializing d and f. 
byte z = 22;                // definition and initializes z. 
char x = 'x';               // the variable x has the value 'x'.

Pour une définition sans initialiseur: les variables avec une durée de stockage statique sont implicitement initialisées avec NULL (tous les octets ont la valeur 0); la valeur initiale de toutes les autres variables n'est pas définie.

Déclaration de variable en C ++

Une déclaration de variable fournit l'assurance au compilateur qu'il existe une variable avec le type et le nom donnés afin que le compilateur procède à une compilation ultérieure sans avoir besoin de détails complets sur la variable. Une déclaration de variable n'a sa signification qu'au moment de la compilation, le compilateur a besoin d'une définition de variable réelle au moment de la liaison du programme.

Une déclaration de variable est utile lorsque vous utilisez plusieurs fichiers et que vous définissez votre variable dans l'un des fichiers qui seront disponibles au moment de la liaison du programme. Vous utiliserezexternmot-clé pour déclarer une variable à tout endroit. Bien que vous puissiez déclarer une variable plusieurs fois dans votre programme C ++, elle ne peut être définie qu'une seule fois dans un fichier, une fonction ou un bloc de code.

Exemple

Essayez l'exemple suivant où une variable a été déclarée en haut, mais elle a été définie dans la fonction principale -

#include <iostream>
using namespace std;

// Variable declaration:
extern int a, b;
extern int c;
extern float f;
  
int main () {
   // Variable definition:
   int a, b;
   int c;
   float f;
 
   // actual initialization
   a = 10;
   b = 20;
   c = a + b;
 
   cout << c << endl ;

   f = 70.0/3.0;
   cout << f << endl ;
 
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

30
23.3333

Le même concept s'applique à la déclaration de fonction où vous fournissez un nom de fonction au moment de sa déclaration et sa définition réelle peut être donnée n'importe où ailleurs. Par exemple -

// function declaration
int func();
int main() {
   // function call
   int i = func();
}

// function definition
int func() {
   return 0;
}

Lvalues ​​et Rvalues

Il existe deux types d'expressions en C ++ -

  • lvalue- Les expressions qui font référence à un emplacement mémoire sont appelées expression "lvalue". Une lvalue peut apparaître comme le côté gauche ou droit d'une affectation.

  • rvalue- Le terme rvalue fait référence à une valeur de données qui est stockée à une certaine adresse en mémoire. Une rvalue est une expression qui ne peut pas avoir de valeur assignée, ce qui signifie qu'une rvalue peut apparaître sur le côté droit mais pas gauche d'une affectation.

Les variables sont des valeurs l et peuvent donc apparaître sur le côté gauche d'une affectation. Les littéraux numériques sont des rvalues ​​et ne peuvent donc pas être affectés et ne peuvent pas apparaître sur le côté gauche. Voici une déclaration valide -

int g = 20;

Mais ce qui suit n'est pas une instruction valide et générerait une erreur de compilation -

10 = 20;

Une portée est une région du programme et, en gros, il y a trois endroits où les variables peuvent être déclarées -

  • A l'intérieur d'une fonction ou d'un bloc appelé variables locales,

  • Dans la définition des paramètres de fonction que l'on appelle paramètres formels.

  • En dehors de toutes les fonctions appelées variables globales.

Nous apprendrons ce qu'est une fonction et son paramètre dans les chapitres suivants. Expliquons ici ce que sont les variables locales et globales.

Variables locales

Les variables déclarées à l'intérieur d'une fonction ou d'un bloc sont des variables locales. Ils ne peuvent être utilisés que par des instructions qui se trouvent à l'intérieur de cette fonction ou de ce bloc de code. Les variables locales ne sont pas connues pour fonctionner en dehors des leurs. Voici l'exemple utilisant des variables locales -

#include <iostream>
using namespace std;
 
int main () {
   // Local variable declaration:
   int a, b;
   int c;
 
   // actual initialization
   a = 10;
   b = 20;
   c = a + b;
 
   cout << c;
 
   return 0;
}

Variables globales

Les variables globales sont définies en dehors de toutes les fonctions, généralement au-dessus du programme. Les variables globales conserveront leur valeur pendant toute la durée de vie de votre programme.

Une variable globale est accessible par n'importe quelle fonction. Autrement dit, une variable globale est disponible pour une utilisation dans tout votre programme après sa déclaration. Voici l'exemple utilisant des variables globales et locales -

#include <iostream>
using namespace std;
 
// Global variable declaration:
int g;
 
int main () {
   // Local variable declaration:
   int a, b;
 
   // actual initialization
   a = 10;
   b = 20;
   g = a + b;
  
   cout << g;
 
   return 0;
}

Un programme peut avoir le même nom pour les variables locales et globales mais la valeur de la variable locale à l'intérieur d'une fonction aura la préférence. Par exemple -

#include <iostream>
using namespace std;
 
// Global variable declaration:
int g = 20;
 
int main () {
   // Local variable declaration:
   int g = 10;
 
   cout << g;
 
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

10

Initialisation des variables locales et globales

Lorsqu'une variable locale est définie, elle n'est pas initialisée par le système, vous devez l'initialiser vous-même. Les variables globales sont initialisées automatiquement par le système lorsque vous les définissez comme suit -

Type de données Initialiseur
int 0
carboniser «\ 0»
flotte 0
double 0
aiguille NUL

C'est une bonne pratique de programmation d'initialiser correctement les variables, sinon le programme produirait parfois un résultat inattendu.

Les constantes font référence à des valeurs fixes que le programme ne peut pas modifier et sont appelées literals.

Les constantes peuvent être de l'un des types de données de base et peuvent être divisées en nombres entiers, nombres à virgule flottante, caractères, chaînes et valeurs booléennes.

Encore une fois, les constantes sont traitées comme des variables régulières sauf que leurs valeurs ne peuvent pas être modifiées après leur définition.

Littéraux entiers

Un littéral entier peut être une constante décimale, octale ou hexadécimale. Un préfixe spécifie la base ou la base: 0x ou 0X pour hexadécimal, 0 pour octal et rien pour décimal.

Un littéral entier peut également avoir un suffixe qui est une combinaison de U et L, pour unsigned et long, respectivement. Le suffixe peut être en majuscules ou en minuscules et peut être dans n'importe quel ordre.

Voici quelques exemples de littéraux entiers -

212         // Legal
215u        // Legal
0xFeeL      // Legal
078         // Illegal: 8 is not an octal digit
032UU       // Illegal: cannot repeat a suffix

Voici d'autres exemples de divers types de littéraux entiers -

85         // decimal
0213       // octal
0x4b       // hexadecimal
30         // int
30u        // unsigned int
30l        // long
30ul       // unsigned long

Littéraux à virgule flottante

Un littéral à virgule flottante a une partie entière, une virgule décimale, une partie fractionnaire et une partie exposant. Vous pouvez représenter des littéraux à virgule flottante sous forme décimale ou exponentielle.

Lors de la représentation sous forme décimale, vous devez inclure la virgule décimale, l'exposant ou les deux et, lors de la représentation sous forme exponentielle, vous devez inclure la partie entière, la partie fractionnaire ou les deux. L'exposant signé est introduit par e ou E.

Voici quelques exemples de littéraux à virgule flottante -

3.14159       // Legal
314159E-5L    // Legal
510E          // Illegal: incomplete exponent
210f          // Illegal: no decimal or exponent
.e55          // Illegal: missing integer or fraction

Littéraux booléens

Il existe deux littéraux booléens et ils font partie des mots-clés C ++ standard -

  • Une valeur de true représentant vrai.

  • Une valeur de false représentant faux.

Vous ne devez pas considérer la valeur de true égale à 1 et la valeur de false égale à 0.

Littéraux de caractères

Les caractères littéraux sont placés entre guillemets simples. Si le littéral commence par L (majuscule uniquement), il s'agit d'un littéral de caractère large (par exemple, L'x ') et doit être stocké danswchar_ttype de variable. Sinon, il s'agit d'un littéral de caractère étroit (par exemple, 'x') et peut être stocké dans une simple variable dechar type.

Un littéral de caractère peut être un caractère simple (par exemple, «x»), une séquence d'échappement (par exemple, «\ t») ou un caractère universel (par exemple, «\ u02C0»).

Il y a certains caractères en C ++ quand ils sont précédés d'une barre oblique inverse, ils auront une signification spéciale et ils sont utilisés pour représenter comme une nouvelle ligne (\ n) ou une tabulation (\ t). Ici, vous avez une liste de certains de ces codes de séquence d'échappement -

Séquence d'échappement Sens
\\ \ personnage
\ ' ' personnage
\ " " personnage
\? ? personnage
\une Alerte ou cloche
\ b Retour arrière
\F Saut de formulaire
\ n Nouvelle ligne
\ r Retour chariot
\ t Onglet horizontal
\ v Onglet vertical
\ ooo Numéro octal de un à trois chiffres
\ xhh. . . Nombre hexadécimal d'un ou plusieurs chiffres

Voici l'exemple pour montrer quelques caractères de séquence d'échappement -

#include <iostream>
using namespace std;

int main() {
   cout << "Hello\tWorld\n\n";
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Hello   World

Littéraux de chaîne

Les chaînes littérales sont placées entre guillemets. Une chaîne contient des caractères similaires aux littéraux de caractères: caractères simples, séquences d'échappement et caractères universels.

Vous pouvez diviser une longue ligne en plusieurs lignes à l'aide de chaînes littérales et les séparer en utilisant des espaces.

Voici quelques exemples de littéraux de chaîne. Les trois formes sont des chaînes identiques.

"hello, dear"

"hello, \

dear"

"hello, " "d" "ear"

Définition des constantes

Il existe deux méthodes simples en C ++ pour définir des constantes -

  • En utilisant #define préprocesseur.

  • En utilisant const mot-clé.

Le préprocesseur #define

Voici le formulaire pour utiliser le préprocesseur #define pour définir une constante -

#define identifier value

L'exemple suivant l'explique en détail -

#include <iostream>
using namespace std;

#define LENGTH 10   
#define WIDTH  5
#define NEWLINE '\n'

int main() {
   int area;  
   
   area = LENGTH * WIDTH;
   cout << area;
   cout << NEWLINE;
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

50

Le mot-clé const

Vous pouvez utiliser const préfixe pour déclarer des constantes avec un type spécifique comme suit -

const type variable = value;

L'exemple suivant l'explique en détail -

#include <iostream>
using namespace std;

int main() {
   const int  LENGTH = 10;
   const int  WIDTH  = 5;
   const char NEWLINE = '\n';
   int area;  
   
   area = LENGTH * WIDTH;
   cout << area;
   cout << NEWLINE;
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

50

Notez que c'est une bonne pratique de programmation de définir des constantes dans CAPITALS.

C ++ permet le char, int, et doubleles types de données doivent être précédés de modificateurs. Un modificateur est utilisé pour modifier la signification du type de base afin qu'il corresponde plus précisément aux besoins de diverses situations.

Les modificateurs de type de données sont répertoriés ici -

  • signed
  • unsigned
  • long
  • short

Les modificateurs signed, unsigned, long, et shortpeut être appliqué aux types de base entiers. En plus,signed et unsigned peut être appliqué à char, et long peut être appliqué pour doubler.

Les modificateurs signed et unsigned peut également être utilisé comme préfixe pour long ou shortmodificateurs. Par exemple,unsigned long int.

C ++ permet une notation abrégée pour déclarer unsigned, short, ou longentiers. Vous pouvez simplement utiliser le motunsigned, short, ou long, sans pour autant int. Cela implique automatiquementint. Par exemple, les deux instructions suivantes déclarent toutes deux des variables entières non signées.

unsigned x;
unsigned int y;

Pour comprendre la différence entre la façon dont les modificateurs d'entiers signés et non signés sont interprétés par C ++, vous devez exécuter le programme court suivant -

#include <iostream>
using namespace std;
 
/* This program shows the difference between
   * signed and unsigned integers.
*/
int main() {
   short int i;           // a signed short integer
   short unsigned int j;  // an unsigned short integer

   j = 50000;

   i = j;
   cout << i << " " << j;

   return 0;
}

Lorsque ce programme est exécuté, voici la sortie -

-15536 50000

Le résultat ci-dessus est dû au fait que le modèle de bits qui représente 50 000 comme un entier court non signé est interprété comme -15 536 par un court.

Qualificateurs de type en C ++

Les qualificateurs de type fournissent des informations supplémentaires sur les variables qu'ils précèdent.

Sr.Non Qualificatif et signification
1

const

Objets de type const ne peut pas être modifié par votre programme pendant l'exécution.

2

volatile

Le modificateur volatile indique au compilateur que la valeur d'une variable peut être modifiée d'une manière non explicitement spécifiée par le programme.

3

restrict

Un pointeur qualifié par restrictest initialement le seul moyen par lequel l'objet vers lequel il pointe est accessible. Seul C99 ajoute un nouveau qualificatif de type appelé restrict.

Une classe de stockage définit la portée (visibilité) et la durée de vie des variables et / ou des fonctions dans un programme C ++. Ces spécificateurs précèdent le type qu'ils modifient. Il existe les classes de stockage suivantes, qui peuvent être utilisées dans un programme C ++

  • auto
  • register
  • static
  • extern
  • mutable

La classe de stockage automatique

le auto la classe de stockage est la classe de stockage par défaut pour toutes les variables locales.

{
   int mount;
   auto int month;
}

L'exemple ci-dessus définit deux variables avec la même classe de stockage, auto ne peut être utilisé que dans des fonctions, c'est-à-dire des variables locales.

La classe de stockage de registre

le registerLa classe de stockage est utilisée pour définir les variables locales qui doivent être stockées dans un registre au lieu de la RAM. Cela signifie que la variable a une taille maximale égale à la taille du registre (généralement un mot) et ne peut pas avoir l'opérateur unaire '&' appliqué (car elle n'a pas d'emplacement mémoire).

{
   register int  miles;
}

Le registre ne doit être utilisé que pour les variables nécessitant un accès rapide telles que les compteurs. Il convient également de noter que la définition de «registre» ne signifie pas que la variable sera stockée dans un registre. Cela signifie qu'il PEUT être stocké dans un registre en fonction des restrictions matérielles et d'implémentation.

La classe de stockage statique

le staticstorage class indique au compilateur de conserver une variable locale pendant la durée de vie du programme au lieu de la créer et de la détruire chaque fois qu'elle entre et sort de la portée. Par conséquent, rendre les variables locales statiques leur permet de conserver leurs valeurs entre les appels de fonction.

Le modificateur statique peut également être appliqué aux variables globales. Lorsque cela est fait, la portée de cette variable est restreinte au fichier dans lequel elle est déclarée.

En C ++, lorsque statique est utilisé sur un membre de données de classe, une seule copie de ce membre est partagée par tous les objets de sa classe.

#include <iostream>
 
// Function declaration
void func(void);
 
static int count = 10; /* Global variable */
 
main() {
   while(count--) {
      func();
   }
   
   return 0;
}

// Function definition
void func( void ) {
   static int i = 5; // local static variable
   i++;
   std::cout << "i is " << i ;
   std::cout << " and count is " << count << std::endl;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

i is 6 and count is 9
i is 7 and count is 8
i is 8 and count is 7
i is 9 and count is 6
i is 10 and count is 5
i is 11 and count is 4
i is 12 and count is 3
i is 13 and count is 2
i is 14 and count is 1
i is 15 and count is 0

La classe de stockage externe

le externLa classe de stockage est utilisée pour donner une référence à une variable globale visible par TOUS les fichiers programme. Lorsque vous utilisez «extern», la variable ne peut pas être initialisée car elle ne fait que pointer le nom de la variable vers un emplacement de stockage précédemment défini.

Lorsque vous avez plusieurs fichiers et que vous définissez une variable globale ou une fonction, qui sera également utilisée dans d'autres fichiers, alors extern sera utilisé dans un autre fichier pour donner la référence à la variable ou à la fonction définie. Juste pour comprendre, extern est utilisé pour déclarer une variable globale ou une fonction dans un autre fichier.

Le modificateur extern est le plus couramment utilisé lorsqu'il y a deux fichiers ou plus partageant les mêmes variables globales ou fonctions comme expliqué ci-dessous.

Premier fichier: main.cpp

#include <iostream>
int count ;
extern void write_extern();
 
main() {
   count = 5;
   write_extern();
}

Deuxième fichier: support.cpp

#include <iostream>

extern int count;

void write_extern(void) {
   std::cout << "Count is " << count << std::endl;
}

Ici, le mot clé extern est utilisé pour déclarer le nombre dans un autre fichier. Maintenant, compilez ces deux fichiers comme suit -

$g++ main.cpp support.cpp -o write

Cela produira write programme exécutable, essayez d'exécuter write et vérifiez le résultat comme suit -

$./write
5

La classe de stockage mutable

le mutableLe spécificateur s'applique uniquement aux objets de classe, qui sont abordés plus loin dans ce didacticiel. Il permet à un membre d'un objet de remplacer la fonction membre const. Autrement dit, un membre mutable peut être modifié par une fonction membre const.

Un opérateur est un symbole qui indique au compilateur d'effectuer des manipulations mathématiques ou logiques spécifiques. C ++ est riche en opérateurs intégrés et fournit les types d'opérateurs suivants -

  • Opérateurs arithmétiques
  • Opérateurs relationnels
  • Opérateurs logiques
  • Opérateurs au niveau du bit
  • Opérateurs d'affectation
  • Opérateurs divers

Ce chapitre examinera les opérateurs arithmétique, relationnel, logique, binaire, d'affectation et autres un par un.

Opérateurs arithmétiques

Les opérateurs arithmétiques suivants sont pris en charge par le langage C ++ -

Supposons que la variable A vaut 10 et la variable B 20, alors -

Afficher des exemples

Opérateur La description Exemple
+ Ajoute deux opérandes A + B donnera 30
- Soustrait le deuxième opérande du premier A - B donnera -10
* Multiplie les deux opérandes A * B donnera 200
/ Divise le numérateur par le dénumérateur B / A donnera 2
% Opérateur de module et reste après une division entière B% A donnera 0
++ Opérateur d'incrémentation , augmente la valeur entière de un A ++ donnera 11
- Décrémenter l'opérateur , diminue la valeur entière de un A-- donnera 9

Opérateurs relationnels

Les opérateurs relationnels suivants sont pris en charge par le langage C ++

Supposons que la variable A vaut 10 et la variable B 20, alors -

Afficher des exemples

Opérateur La description Exemple
== Vérifie si les valeurs de deux opérandes sont égales ou non, si oui, la condition devient vraie. (A == B) n'est pas vrai.
! = Vérifie si les valeurs de deux opérandes sont égales ou non, si les valeurs ne sont pas égales, la condition devient vraie. (A! = B) est vrai.
> Vérifie si la valeur de l'opérande gauche est supérieure à la valeur de l'opérande droit, si oui, la condition devient vraie. (A> B) n'est pas vrai.
< Vérifie si la valeur de l'opérande gauche est inférieure à la valeur de l'opérande droit, si oui, la condition devient vraie. (A <B) est vrai.
> = Vérifie si la valeur de l'opérande gauche est supérieure ou égale à la valeur de l'opérande droit, si oui, la condition devient vraie. (A> = B) n'est pas vrai.
<= Vérifie si la valeur de l'opérande gauche est inférieure ou égale à la valeur de l'opérande droit, si oui, la condition devient vraie. (A <= B) est vrai.

Opérateurs logiques

Les opérateurs logiques suivants sont pris en charge par le langage C ++.

Supposons que la variable A vaut 1 et la variable B vaut 0, alors -

Afficher des exemples

Opérateur La description Exemple
&& Opérateur logique ET appelé. Si les deux opérandes sont différents de zéro, la condition devient vraie. (A && B) est faux.
|| Opérateur OU logique appelé. Si l'un des deux opérandes est différent de zéro, la condition devient vraie. (A || B) est vrai.
! Opérateur PAS logique appelé. Utilisez pour inverser l'état logique de son opérande. Si une condition est vraie, alors l'opérateur logique NOT rendra faux. ! (A && B) est vrai.

Opérateurs au niveau du bit

L'opérateur au niveau du bit fonctionne sur les bits et effectue des opérations bit par bit. Les tables de vérité pour &, | et ^ sont les suivantes:

p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

Supposons que A = 60; et B = 13; maintenant au format binaire, ils seront comme suit -

A = 0011 1100

B = 0000 1101

-----------------

A&B = 0000 1100

A | B = 0011 1101

A ^ B = 0011 0001

~ A = 1100 0011

Les opérateurs Bitwise pris en charge par le langage C ++ sont répertoriés dans le tableau suivant. Supposons que la variable A a 60 et la variable B 13, alors -

Afficher des exemples

Opérateur La description Exemple
& L'opérateur binaire AND copie un peu le résultat s'il existe dans les deux opérandes. (A & B) donnera 12 qui est 0000 1100
| L'opérateur OR binaire copie un bit s'il existe dans l'un ou l'autre des opérandes. (A | B) donnera 61 qui est 0011 1101
^ L'opérateur XOR binaire copie le bit s'il est défini dans un opérande mais pas dans les deux. (A ^ B) donnera 49 qui est 0011 0001
~ L'opérateur de complément Binary Ones est unaire et a pour effet de «retourner» les bits. (~ A) donnera -61 qui est 1100 0011 sous forme de complément à 2 en raison d'un nombre binaire signé.
<< Opérateur de décalage binaire gauche. La valeur des opérandes de gauche est déplacée vers la gauche du nombre de bits spécifié par l'opérande de droite. Un << 2 donnera 240, soit 1111 0000
>> Opérateur de décalage binaire vers la droite. La valeur des opérandes de gauche est déplacée vers la droite du nombre de bits spécifié par l'opérande de droite. Un >> 2 donnera 15, soit 0000 1111

Opérateurs d'affectation

Les opérateurs d'affectation suivants sont pris en charge par le langage C ++ -

Afficher des exemples

Opérateur La description Exemple
= Opérateur d'affectation simple, affecte les valeurs des opérandes du côté droit à l'opérande du côté gauche. C = A + B attribuera la valeur de A + B à C
+ = Ajouter l'opérateur d'affectation ET, il ajoute l'opérande droit à l'opérande gauche et affecte le résultat à l'opérande gauche. C + = A équivaut à C = C + A
- = Soustraire l'opérateur d'affectation ET, il soustrait l'opérande droit de l'opérande gauche et attribue le résultat à l'opérande gauche. C - = A équivaut à C = C - A
* = Multiplier l'opérateur d'affectation ET, il multiplie l'opérande droit par l'opérande gauche et affecte le résultat à l'opérande gauche. C * = A équivaut à C = C * A
/ = Opérateur d'affectation de division ET, il divise l'opérande de gauche avec l'opérande de droite et affecte le résultat à l'opérande de gauche. C / = A équivaut à C = C / A
% = Opérateur d'assignation de module ET, il prend le module en utilisant deux opérandes et affecte le résultat à l'opérande de gauche. C% = A équivaut à C = C% A
<< = Opérateur de décalage ET d'affectation gauche. C << = 2 est identique à C = C << 2
>> = Opérateur de décalage ET d'affectation à droite. C >> = 2 est identique à C = C >> 2
& = Opérateur d'affectation AND au niveau du bit. C & = 2 est identique à C = C & 2
^ = Opérateur OU exclusif et d'affectation au niveau du bit. C ^ = 2 est identique à C = C ^ 2
| = Opérateur OU et d'affectation inclusif au niveau du bit. C | = 2 est identique à C = C | 2

Opérateurs divers

Le tableau suivant répertorie d'autres opérateurs pris en charge par C ++.

Sr.Non Opérateur et description
1

sizeof

L'opérateur sizeof renvoie la taille d'une variable. Par exemple, sizeof (a), où 'a' est un entier, et retournera 4.

2

Condition ? X : Y

Opérateur conditionnel (?) . Si Condition est vraie, elle renvoie la valeur de X sinon la valeur de Y.

3

,

L'opérateur virgule provoque l'exécution d'une séquence d'opérations. La valeur de l'expression entière par virgule est la valeur de la dernière expression de la liste séparée par des virgules.

4

. (dot) and -> (arrow)

Les opérateurs membres sont utilisés pour référencer les membres individuels des classes, des structures et des syndicats.

5

Cast

Les opérateurs de diffusion convertissent un type de données en un autre. Par exemple, int (2.2000) renverrait 2.

6

&

Opérateur de pointeur & renvoie l'adresse d'une variable. Par exemple & a; donnera l'adresse réelle de la variable.

sept

*

L'opérateur de pointeur * est un pointeur vers une variable. Par exemple * var; pointera vers une variable var.

Priorité des opérateurs en C ++

La priorité des opérateurs détermine le regroupement des termes dans une expression. Cela affecte la manière dont une expression est évaluée. Certains opérateurs ont une priorité plus élevée que d'autres; par exemple, l'opérateur de multiplication a une priorité plus élevée que l'opérateur d'addition -

Par exemple x = 7 + 3 * 2; ici, x est attribué à 13, et non à 20 car l'opérateur * a une priorité plus élevée que +, il est donc d'abord multiplié par 3 * 2, puis ajouté en 7.

Ici, les opérateurs avec la priorité la plus élevée apparaissent en haut du tableau, ceux avec la priorité la plus basse apparaissent en bas. Dans une expression, les opérateurs de priorité supérieure seront évalués en premier.

Afficher des exemples

Catégorie  Opérateur  Associativité 
Postfix  () [] ->. ++ - -   De gauche à droite 
Unaire  + -! ~ ++ - - (type) * & sizeof  De droite à gauche 
Multiplicatif   * /%  De gauche à droite 
Additif   + -  De gauche à droite 
Décalage   << >>  De gauche à droite 
Relationnel   <<=>> =  De gauche à droite 
Égalité   ==! =  De gauche à droite 
ET au niveau du bit  De gauche à droite 
XOR au niveau du bit  De gauche à droite 
OU au niveau du bit  De gauche à droite 
ET logique  &&  De gauche à droite 
OU logique  ||  De gauche à droite 
Conditionnel  ?:  De droite à gauche 
Affectation  = + = - = * = / =% = >> = << = & = ^ = | =  De droite à gauche 
Virgule  De gauche à droite 

Il peut arriver que vous deviez exécuter un bloc de code plusieurs fois. En général, les instructions sont exécutées de manière séquentielle: la première instruction d'une fonction est exécutée en premier, suivie de la seconde, et ainsi de suite.

Les langages de programmation fournissent diverses structures de contrôle qui permettent des chemins d'exécution plus compliqués.

Une instruction de boucle nous permet d'exécuter une instruction ou un groupe d'instructions plusieurs fois et ce qui suit est le général à partir d'une instruction de boucle dans la plupart des langages de programmation -

Le langage de programmation C ++ fournit le type de boucles suivant pour gérer les exigences de bouclage.

Sr.Non Type de boucle et description
1 boucle while

Répète une instruction ou un groupe d'instructions tant qu'une condition donnée est vraie. Il teste la condition avant d'exécuter le corps de la boucle.

2 pour boucle

Exécute une séquence d'instructions plusieurs fois et abrége le code qui gère la variable de boucle.

3 faire ... boucle while

Comme une instruction 'while', sauf qu'elle teste la condition à la fin du corps de la boucle.

4 boucles imbriquées

Vous pouvez utiliser une ou plusieurs boucles dans n'importe quelle autre boucle «while», «for» ou «do.. while».

Déclarations de contrôle de boucle

Les instructions de contrôle de boucle modifient l'exécution de sa séquence normale. Lorsque l'exécution quitte une étendue, tous les objets automatiques qui ont été créés dans cette étendue sont détruits.

C ++ prend en charge les instructions de contrôle suivantes.

Sr.Non Déclaration de contrôle et description
1 déclaration break

Met fin au loop ou switch et transfère l'exécution à l'instruction immédiatement après la boucle ou le commutateur.

2 continue déclaration

Force la boucle à ignorer le reste de son corps et à retester immédiatement son état avant de réitérer.

3 déclaration goto

Transfère le contrôle vers l'instruction étiquetée. Bien qu'il ne soit pas conseillé d'utiliser l'instruction goto dans votre programme.

La boucle infinie

Une boucle devient une boucle infinie si une condition ne devient jamais fausse. leforLa boucle est traditionnellement utilisée à cette fin. Étant donné qu'aucune des trois expressions qui forment la boucle «for» n'est requise, vous pouvez créer une boucle sans fin en laissant l'expression conditionnelle vide.

#include <iostream>
using namespace std;
 
int main () {
   for( ; ; ) {
      printf("This loop will run forever.\n");
   }

   return 0;
}

Lorsque l'expression conditionnelle est absente, elle est supposée vraie. Vous pouvez avoir une expression d'initialisation et d'incrémentation, mais les programmeurs C ++ utilisent plus couramment la construction «for (;;)» pour signifier une boucle infinie.

NOTE - Vous pouvez terminer une boucle infinie en appuyant sur les touches Ctrl + C.

Les structures de prise de décision exigent que le programmeur spécifie une ou plusieurs conditions à évaluer ou à tester par le programme, ainsi qu'une ou plusieurs instructions à exécuter si la condition est jugée vraie, et éventuellement d'autres instructions à exécuter si la condition est déterminé comme étant faux.

Voici la forme générale d'une structure de prise de décision typique trouvée dans la plupart des langages de programmation -

Le langage de programmation C ++ fournit les types suivants d'instructions de prise de décision.

Sr.Non Déclaration et description
1 si déclaration

Une instruction 'if' consiste en une expression booléenne suivie d'une ou plusieurs instructions.

2 instruction if ... else

Une instruction 'if' peut être suivie d'une instruction 'else' facultative, qui s'exécute lorsque l'expression booléenne est fausse.

3 instruction switch

Une instruction 'switch' permet à une variable d'être testée pour l'égalité par rapport à une liste de valeurs.

4 instructions if imbriquées

Vous pouvez utiliser une instruction «if» ou «else if» dans une ou plusieurs instructions «if» ou «else if».

5 instructions de commutateur imbriquées

Vous pouvez utiliser une instruction 'switch' dans une ou plusieurs autres instructions 'switch'.

Le ? : Opérateur

Nous avons couvert l' opérateur conditionnel »? : ” Dans le chapitre précédent qui peut être utilisé pour remplacerif...elsedéclarations. Il a la forme générale suivante -

Exp1 ? Exp2 : Exp3;

Exp1, Exp2 et Exp3 sont des expressions. Notez l'utilisation et le placement des deux points.

La valeur d'un "?" expression est déterminée comme ceci: Exp1 est évalué. Si c'est vrai, alors Exp2 est évalué et devient la valeur de l'ensemble '?' expression. Si Exp1 est faux, Exp3 est évalué et sa valeur devient la valeur de l'expression.

Une fonction est un groupe d'instructions qui exécutent ensemble une tâche. Chaque programme C ++ a au moins une fonction, qui estmain(), et tous les programmes les plus triviaux peuvent définir des fonctions supplémentaires.

Vous pouvez diviser votre code en fonctions distinctes. La façon dont vous divisez votre code entre différentes fonctions dépend de vous, mais logiquement, la division est généralement telle que chaque fonction effectue une tâche spécifique.

Une fonction declarationindique au compilateur le nom, le type de retour et les paramètres d'une fonction. Une fonctiondefinition fournit le corps réel de la fonction.

La bibliothèque standard C ++ fournit de nombreuses fonctions intégrées que votre programme peut appeler. Par exemple, fonctionstrcat() pour concaténer deux chaînes, fonction memcpy() pour copier un emplacement mémoire vers un autre emplacement et de nombreuses autres fonctions.

Une fonction est connue sous différents noms comme une méthode ou une sous-routine ou une procédure etc.

Définition d'une fonction

La forme générale d'une définition de fonction C ++ est la suivante -

return_type function_name( parameter list ) {
   body of the function
}

Une définition de fonction C ++ se compose d'un en-tête de fonction et d'un corps de fonction. Voici toutes les parties d'une fonction -

  • Return Type- Une fonction peut renvoyer une valeur. lereturn_typeest le type de données de la valeur renvoyée par la fonction. Certaines fonctions exécutent les opérations souhaitées sans renvoyer de valeur. Dans ce cas, le return_type est le mot-clévoid.

  • Function Name- Ceci est le nom réel de la fonction. Le nom de la fonction et la liste des paramètres constituent ensemble la signature de la fonction.

  • Parameters- Un paramètre est comme un espace réservé. Lorsqu'une fonction est appelée, vous transmettez une valeur au paramètre. Cette valeur est appelée paramètre ou argument réel. La liste des paramètres fait référence au type, à l'ordre et au nombre de paramètres d'une fonction. Les paramètres sont facultatifs; autrement dit, une fonction peut ne contenir aucun paramètre.

  • Function Body - Le corps de la fonction contient une collection d'instructions qui définissent ce que fait la fonction.

Exemple

Voici le code source d'une fonction appelée max(). Cette fonction prend deux paramètres num1 et num2 et renvoie le plus grand des deux -

// function returning the max between two numbers
 
int max(int num1, int num2) {
   // local variable declaration
   int result;
 
   if (num1 > num2)
      result = num1;
   else
      result = num2;
 
   return result; 
}

Déclarations de fonction

Une fonction declarationindique au compilateur un nom de fonction et comment appeler la fonction. Le corps réel de la fonction peut être défini séparément.

Une déclaration de fonction comprend les parties suivantes -

return_type function_name( parameter list );

Pour la fonction max () définie ci-dessus, voici la déclaration de fonction -

int max(int num1, int num2);

Les noms de paramètres ne sont pas importants dans la déclaration de fonction, seul leur type est requis, ce qui suit est également une déclaration valide -

int max(int, int);

La déclaration de fonction est requise lorsque vous définissez une fonction dans un fichier source et que vous appelez cette fonction dans un autre fichier. Dans ce cas, vous devez déclarer la fonction en haut du fichier appelant la fonction.

Appeler une fonction

Lors de la création d'une fonction C ++, vous donnez une définition de ce que la fonction doit faire. Pour utiliser une fonction, vous devrez appeler ou invoquer cette fonction.

Lorsqu'un programme appelle une fonction, le contrôle du programme est transféré à la fonction appelée. Une fonction appelée exécute une tâche définie et quand son instruction return est exécutée ou lorsque son accolade fermante de fin de fonction est atteinte, elle renvoie le contrôle du programme au programme principal.

Pour appeler une fonction, vous devez simplement transmettre les paramètres requis avec le nom de la fonction, et si la fonction renvoie une valeur, vous pouvez stocker la valeur renvoyée. Par exemple -

#include <iostream>
using namespace std;
 
// function declaration
int max(int num1, int num2);
 
int main () {
   // local variable declaration:
   int a = 100;
   int b = 200;
   int ret;
 
   // calling a function to get max value.
   ret = max(a, b);
   cout << "Max value is : " << ret << endl;
 
   return 0;
}
 
// function returning the max between two numbers
int max(int num1, int num2) {
   // local variable declaration
   int result;
 
   if (num1 > num2)
      result = num1;
   else
      result = num2;
 
   return result; 
}

J'ai conservé la fonction max () avec la fonction main () et compilé le code source. Lors de l'exécution de l'exécutable final, il produirait le résultat suivant -

Max value is : 200

Arguments de fonction

Si une fonction doit utiliser des arguments, elle doit déclarer des variables qui acceptent les valeurs des arguments. Ces variables sont appeléesformal parameters de la fonction.

Les paramètres formels se comportent comme les autres variables locales à l'intérieur de la fonction et sont créés à l'entrée dans la fonction et détruits à la sortie.

Lors de l'appel d'une fonction, il existe deux manières de passer des arguments à une fonction -

Sr.Non Type d'appel et description
1 Appel par valeur

Cette méthode copie la valeur réelle d'un argument dans le paramètre formel de la fonction. Dans ce cas, les modifications apportées au paramètre à l'intérieur de la fonction n'ont aucun effet sur l'argument.

2 Appel par pointeur

Cette méthode copie l'adresse d'un argument dans le paramètre formel. À l'intérieur de la fonction, l'adresse est utilisée pour accéder à l'argument réel utilisé dans l'appel. Cela signifie que les modifications apportées au paramètre affectent l'argument.

3 Appel par référence

Cette méthode copie la référence d'un argument dans le paramètre formel. À l'intérieur de la fonction, la référence est utilisée pour accéder à l'argument réel utilisé dans l'appel. Cela signifie que les modifications apportées au paramètre affectent l'argument.

Par défaut, C ++ utilise call by valuepour passer des arguments. En général, cela signifie que le code dans une fonction ne peut pas modifier les arguments utilisés pour appeler la fonction et l'exemple mentionné ci-dessus tout en appelant la fonction max () utilise la même méthode.

Valeurs par défaut des paramètres

Lorsque vous définissez une fonction, vous pouvez spécifier une valeur par défaut pour chacun des derniers paramètres. Cette valeur sera utilisée si l'argument correspondant est laissé vide lors de l'appel à la fonction.

Cela se fait en utilisant l'opérateur d'affectation et en attribuant des valeurs aux arguments dans la définition de fonction. Si une valeur pour ce paramètre n'est pas transmise lorsque la fonction est appelée, la valeur donnée par défaut est utilisée, mais si une valeur est spécifiée, cette valeur par défaut est ignorée et la valeur transmise est utilisée à la place. Prenons l'exemple suivant -

#include <iostream>
using namespace std;
 
int sum(int a, int b = 20) {
   int result;
   result = a + b;
  
   return (result);
}
int main () {
   // local variable declaration:
   int a = 100;
   int b = 200;
   int result;
 
   // calling a function to add the values.
   result = sum(a, b);
   cout << "Total value is :" << result << endl;

   // calling a function again as follows.
   result = sum(a);
   cout << "Total value is :" << result << endl;
 
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Total value is :300
Total value is :120

Normalement, lorsque nous travaillons avec Numbers, nous utilisons des types de données primitifs tels que int, short, long, float et double, etc. Les types de données numériques, leurs valeurs possibles et les plages de nombres ont été expliqués en discutant des types de données C ++.

Définition de nombres en C ++

Vous avez déjà défini des nombres dans divers exemples donnés dans les chapitres précédents. Voici un autre exemple consolidé pour définir différents types de nombres en C ++ -

#include <iostream>
using namespace std;
 
int main () {
   // number definition:
   short  s;
   int    i;
   long   l;
   float  f;
   double d;
   
   // number assignments;
   s = 10;      
   i = 1000;    
   l = 1000000; 
   f = 230.47;  
   d = 30949.374;
   
   // number printing;
   cout << "short  s :" << s << endl;
   cout << "int    i :" << i << endl;
   cout << "long   l :" << l << endl;
   cout << "float  f :" << f << endl;
   cout << "double d :" << d << endl;
 
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

short  s :10
int    i :1000
long   l :1000000
float  f :230.47
double d :30949.4

Opérations mathématiques en C ++

En plus des diverses fonctions que vous pouvez créer, C ++ comprend également des fonctions utiles que vous pouvez utiliser. Ces fonctions sont disponibles dans les bibliothèques standard C et C ++ et appeléesbuilt-inles fonctions. Ce sont des fonctions qui peuvent être incluses dans votre programme puis utilisées.

C ++ a un riche ensemble d'opérations mathématiques, qui peuvent être effectuées sur différents nombres. Le tableau suivant répertorie quelques fonctions mathématiques intégrées utiles disponibles en C ++.

Pour utiliser ces fonctions, vous devez inclure le fichier d'en-tête mathématique <cmath>.

Sr.Non Fonction et objectif
1

double cos(double);

Cette fonction prend un angle (comme un double) et renvoie le cosinus.

2

double sin(double);

Cette fonction prend un angle (comme un double) et renvoie le sinus.

3

double tan(double);

Cette fonction prend un angle (comme un double) et renvoie la tangente.

4

double log(double);

Cette fonction prend un nombre et renvoie le journal naturel de ce nombre.

5

double pow(double, double);

Le premier est un nombre que vous souhaitez augmenter et le second est la puissance que vous souhaitez augmenter t

6

double hypot(double, double);

Si vous passez à cette fonction la longueur de deux côtés d'un triangle rectangle, elle vous rendra la longueur de l'hypoténuse.

sept

double sqrt(double);

Vous passez à cette fonction un nombre et cela vous donne la racine carrée.

8

int abs(int);

Cette fonction renvoie la valeur absolue d'un entier qui lui est passé.

9

double fabs(double);

Cette fonction renvoie la valeur absolue de tout nombre décimal qui lui est passé.

dix

double floor(double);

Recherche l'entier qui est inférieur ou égal à l'argument qui lui est passé.

Voici un exemple simple pour montrer quelques-unes des opérations mathématiques -

#include <iostream>
#include <cmath>
using namespace std;
 
int main () {
   // number definition:
   short  s = 10;
   int    i = -1000;
   long   l = 100000;
   float  f = 230.47;
   double d = 200.374;

   // mathematical operations;
   cout << "sin(d) :" << sin(d) << endl;
   cout << "abs(i)  :" << abs(i) << endl;
   cout << "floor(d) :" << floor(d) << endl;
   cout << "sqrt(f) :" << sqrt(f) << endl;
   cout << "pow( d, 2) :" << pow(d, 2) << endl;
 
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

sign(d)     :-0.634939
abs(i)      :1000
floor(d)    :200
sqrt(f)     :15.1812
pow( d, 2 ) :40149.7

Nombres aléatoires en C ++

Il existe de nombreux cas où vous souhaiterez générer un nombre aléatoire. Il y a en fait deux fonctions que vous devrez connaître sur la génération de nombres aléatoires. Le premier estrand(), cette fonction ne retournera qu'un nombre pseudo aléatoire. La façon de résoudre ce problème est d'appeler d'abord lesrand() fonction.

Voici un exemple simple pour générer quelques nombres aléatoires. Cet exemple utilisetime() fonction pour obtenir le nombre de secondes sur l'heure de votre système, pour semer aléatoirement la fonction rand () -

#include <iostream>
#include <ctime>
#include <cstdlib>

using namespace std;
 
int main () {
   int i,j;
 
   // set the seed
   srand( (unsigned)time( NULL ) );

   /* generate 10  random numbers. */
   for( i = 0; i < 10; i++ ) {
      // generate actual random number
      j = rand();
      cout <<" Random Number : " << j << endl;
   }

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Random Number : 1748144778
Random Number : 630873888
Random Number : 2134540646
Random Number : 219404170
Random Number : 902129458
Random Number : 920445370
Random Number : 1319072661
Random Number : 257938873
Random Number : 1256201101
Random Number : 580322989

C ++ fournit une structure de données, the array, qui stocke une collection séquentielle de taille fixe d'éléments du même type. Un tableau est utilisé pour stocker une collection de données, mais il est souvent plus utile de considérer un tableau comme une collection de variables du même type.

Au lieu de déclarer des variables individuelles, telles que nombre0, nombre1, ... et nombre99, vous déclarez une variable de tableau telle que des nombres et utilisez les nombres [0], les nombres [1] et ..., les nombres [99] pour représenter variables individuelles. Un élément spécifique d'un tableau est accessible par un index.

Tous les tableaux sont constitués d'emplacements de mémoire contigus. L'adresse la plus basse correspond au premier élément et l'adresse la plus élevée au dernier élément.

Déclaration de tableaux

Pour déclarer un tableau en C ++, le programmeur spécifie le type des éléments et le nombre d'éléments requis par un tableau comme suit -

type arrayName [ arraySize ];

C'est ce qu'on appelle un tableau à une seule dimension. learraySize doit être une constante entière supérieure à zéro et typepeut être n'importe quel type de données C ++ valide. Par exemple, pour déclarer un tableau de 10 éléments appelé balance de type double, utilisez cette instruction -

double balance[10];

Initialisation des tableaux

Vous pouvez initialiser les éléments du tableau C ++ un par un ou en utilisant une seule instruction comme suit -

double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};

Le nombre de valeurs entre accolades {} ne peut pas être supérieur au nombre d'éléments que nous déclarons pour le tableau entre crochets []. Voici un exemple pour affecter un seul élément du tableau -

Si vous omettez la taille du tableau, un tableau juste assez grand pour contenir l'initialisation est créé. Par conséquent, si vous écrivez -

double balance[] = {1000.0, 2.0, 3.4, 17.0, 50.0};

Vous allez créer exactement le même tableau que vous l'avez fait dans l'exemple précédent.

balance[4] = 50.0;

L'instruction ci-dessus attribue au numéro d'élément 5 e dans le tableau une valeur de 50,0. Le tableau avec le 4 ème index sera le 5 ème , c'est-à-dire le dernier élément car tous les tableaux ont 0 comme index de leur premier élément qui est également appelé index de base. Voici la représentation picturale du même tableau que nous avons discuté ci-dessus -

Accès aux éléments de la baie

Un élément est accessible en indexant le nom du tableau. Cela se fait en plaçant l'index de l'élément entre crochets après le nom du tableau. Par exemple -

double salary = balance[9];

L'instruction ci-dessus prendra le 10ème élément du tableau et attribuera la valeur à la variable de salaire. Voici un exemple, qui utilisera tous les trois concepts mentionnés ci-dessus à savoir. déclaration, affectation et accès aux tableaux -

#include <iostream>
using namespace std;
 
#include <iomanip>
using std::setw;
 
int main () {

   int n[ 10 ]; // n is an array of 10 integers
 
   // initialize elements of array n to 0          
   for ( int i = 0; i < 10; i++ ) {
      n[ i ] = i + 100; // set element at location i to i + 100
   }
   cout << "Element" << setw( 13 ) << "Value" << endl;
 
   // output each array element's value                      
   for ( int j = 0; j < 10; j++ ) {
      cout << setw( 7 )<< j << setw( 13 ) << n[ j ] << endl;
   }
 
   return 0;
}

Ce programme utilise setw()fonction pour formater la sortie. Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Element        Value
      0          100
      1          101
      2          102
      3          103
      4          104
      5          105
      6          106
      7          107
      8          108
      9          109

Tableaux en C ++

Les tableaux sont importants pour C ++ et devraient nécessiter beaucoup plus de détails. Il y a quelques concepts importants qui suivent, qui devraient être clairs pour un programmeur C ++ -

Sr.Non Concept et description
1 Tableaux multidimensionnels

C ++ prend en charge les tableaux multidimensionnels. La forme la plus simple du tableau multidimensionnel est le tableau à deux dimensions.

2 Pointeur vers un tableau

Vous pouvez générer un pointeur vers le premier élément d'un tableau en spécifiant simplement le nom du tableau, sans aucun index.

3 Passer des tableaux aux fonctions

Vous pouvez passer à la fonction un pointeur vers un tableau en spécifiant le nom du tableau sans index.

4 Retourne le tableau à partir des fonctions

C ++ permet à une fonction de renvoyer un tableau.

C ++ fournit les deux types de représentations de chaîne suivants:

  • La chaîne de caractères de style C.
  • Le type de classe de chaîne introduit avec le C ++ standard.

La chaîne de caractères de style C

La chaîne de caractères de style C provient du langage C et continue d'être prise en charge dans C ++. Cette chaîne est en fait un tableau unidimensionnel de caractères qui se termine par unnullcaractère '\ 0'. Ainsi, une chaîne terminée par un nul contient les caractères qui composent la chaîne suivie d'unnull.

La déclaration et l'initialisation suivantes créent une chaîne composée du mot "Hello". Pour contenir le caractère nul à la fin du tableau, la taille du tableau de caractères contenant la chaîne est un de plus que le nombre de caractères du mot «Bonjour».

char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

Si vous suivez la règle d'initialisation du tableau, vous pouvez écrire l'instruction ci-dessus comme suit -

char greeting[] = "Hello";

Voici la présentation de la mémoire de la chaîne définie ci-dessus en C / C ++ -

En fait, vous ne placez pas le caractère nul à la fin d'une constante de chaîne. Le compilateur C ++ place automatiquement le '\ 0' à la fin de la chaîne lorsqu'il initialise le tableau. Essayons d'imprimer la chaîne mentionnée ci-dessus -

#include <iostream>

using namespace std;

int main () {

   char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

   cout << "Greeting message: ";
   cout << greeting << endl;

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Greeting message: Hello

C ++ prend en charge un large éventail de fonctions qui manipulent des chaînes terminées par NULL -

Sr.Non Fonction et objectif
1

strcpy(s1, s2);

Copie la chaîne s2 dans la chaîne s1.

2

strcat(s1, s2);

Concatène la chaîne s2 à la fin de la chaîne s1.

3

strlen(s1);

Renvoie la longueur de la chaîne s1.

4

strcmp(s1, s2);

Renvoie 0 si s1 et s2 sont identiques; inférieur à 0 si s1 <s2; supérieur à 0 si s1> s2.

5

strchr(s1, ch);

Renvoie un pointeur sur la première occurrence du caractère ch dans la chaîne s1.

6

strstr(s1, s2);

Renvoie un pointeur vers la première occurrence de la chaîne s2 dans la chaîne s1.

L'exemple suivant utilise quelques-unes des fonctions mentionnées ci-dessus -

#include <iostream>
#include <cstring>

using namespace std;

int main () {

   char str1[10] = "Hello";
   char str2[10] = "World";
   char str3[10];
   int  len ;

   // copy str1 into str3
   strcpy( str3, str1);
   cout << "strcpy( str3, str1) : " << str3 << endl;

   // concatenates str1 and str2
   strcat( str1, str2);
   cout << "strcat( str1, str2): " << str1 << endl;

   // total lenghth of str1 after concatenation
   len = strlen(str1);
   cout << "strlen(str1) : " << len << endl;

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit un résultat comme suit -

strcpy( str3, str1) : Hello
strcat( str1, str2): HelloWorld
strlen(str1) : 10

La classe String en C ++

La bibliothèque C ++ standard fournit un stringtype de classe qui prend en charge toutes les opérations mentionnées ci-dessus, en plus beaucoup plus de fonctionnalités. Vérifions l'exemple suivant -

#include <iostream>
#include <string>

using namespace std;

int main () {

   string str1 = "Hello";
   string str2 = "World";
   string str3;
   int  len ;

   // copy str1 into str3
   str3 = str1;
   cout << "str3 : " << str3 << endl;

   // concatenates str1 and str2
   str3 = str1 + str2;
   cout << "str1 + str2 : " << str3 << endl;

   // total length of str3 after concatenation
   len = str3.size();
   cout << "str3.size() :  " << len << endl;

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit un résultat comme suit -

str3 : Hello
str1 + str2 : HelloWorld
str3.size() :  10

Les pointeurs C ++ sont faciles et amusants à apprendre. Certaines tâches C ++ sont exécutées plus facilement avec des pointeurs, et d'autres tâches C ++, telles que l'allocation de mémoire dynamique, ne peuvent pas être effectuées sans eux.

Comme vous le savez, chaque variable est un emplacement de mémoire et chaque emplacement de mémoire a son adresse définie, accessible à l'aide de l'opérateur perluète (&) qui indique une adresse en mémoire. Considérez ce qui suit qui affichera l'adresse des variables définies -

#include <iostream>

using namespace std;
int main () {
   int  var1;
   char var2[10];

   cout << "Address of var1 variable: ";
   cout << &var1 << endl;

   cout << "Address of var2 variable: ";
   cout << &var2 << endl;

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Address of var1 variable: 0xbfebd5c0
Address of var2 variable: 0xbfebd5b6

Que sont les pointeurs?

UNE pointerest une variable dont la valeur est l'adresse d'une autre variable. Comme toute variable ou constante, vous devez déclarer un pointeur avant de pouvoir l'utiliser. La forme générale d'une déclaration de variable de pointeur est -

type *var-name;

Ici, typeest le type de base du pointeur; il doit s'agir d'un type C ++ valide etvar-nameest le nom de la variable du pointeur. L'astérisque que vous avez utilisé pour déclarer un pointeur est le même que celui que vous utilisez pour la multiplication. Cependant, dans cette instruction, l'astérisque est utilisé pour désigner une variable comme pointeur. Voici la déclaration de pointeur valide -

int    *ip;    // pointer to an integer
double *dp;    // pointer to a double
float  *fp;    // pointer to a float
char   *ch     // pointer to character

Le type de données réel de la valeur de tous les pointeurs, qu'il soit entier, flottant, caractère ou autre, est le même, un long nombre hexadécimal qui représente une adresse mémoire. La seule différence entre les pointeurs de différents types de données est le type de données de la variable ou de la constante vers laquelle pointe le pointeur.

Utilisation de pointeurs en C ++

Il y a peu d'opérations importantes, que nous ferons très fréquemment avec les pointeurs. (a) Nous définissons une variable de pointeur. (b) Attribuez l'adresse d'une variable à un pointeur. (c)Accédez enfin à la valeur à l'adresse disponible dans la variable pointeur. Cela se fait en utilisant l'opérateur unaire * qui renvoie la valeur de la variable située à l'adresse spécifiée par son opérande. L'exemple suivant utilise ces opérations -

#include <iostream>

using namespace std;

int main () {
   int  var = 20;   // actual variable declaration.
   int  *ip;        // pointer variable 

   ip = &var;       // store address of var in pointer variable

   cout << "Value of var variable: ";
   cout << var << endl;

   // print the address stored in ip pointer variable
   cout << "Address stored in ip variable: ";
   cout << ip << endl;

   // access the value at the address available in pointer
   cout << "Value of *ip variable: ";
   cout << *ip << endl;

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit un résultat comme suit -

Value of var variable: 20
Address stored in ip variable: 0xbfc601ac
Value of *ip variable: 20

Pointeurs en C ++

Les pointeurs ont des concepts nombreux mais simples et ils sont très importants pour la programmation C ++. Il existe quelques concepts de pointeurs importants qui devraient être clairs pour un programmeur C ++ -

Sr.Non Concept et description
1 Pointeurs nuls

C ++ prend en charge le pointeur nul, qui est une constante avec une valeur de zéro définie dans plusieurs bibliothèques standard.

2 Arithmétique du pointeur

Il existe quatre opérateurs arithmétiques qui peuvent être utilisés sur les pointeurs: ++, -, +, -

3 Pointeurs vs tableaux

Il existe une relation étroite entre les pointeurs et les tableaux.

4 Tableau de pointeurs

Vous pouvez définir des tableaux pour contenir un certain nombre de pointeurs.

5 Pointeur à pointeur

C ++ vous permet d'avoir un pointeur sur un pointeur et ainsi de suite.

6 Passer des pointeurs aux fonctions

Le passage d'un argument par référence ou par adresse permet tous deux de modifier l'argument passé dans la fonction appelante par la fonction appelée.

sept Pointeur de retour des fonctions

C ++ permet à une fonction de renvoyer un pointeur vers une variable locale, une variable statique et une mémoire allouée dynamiquement.

Une variable de référence est un alias, c'est-à-dire un autre nom pour une variable déjà existante. Une fois qu'une référence est initialisée avec une variable, le nom de la variable ou le nom de la référence peut être utilisé pour faire référence à la variable.

Références vs pointeurs

Les références sont souvent confondues avec les pointeurs, mais trois différences majeures entre les références et les pointeurs sont:

  • Vous ne pouvez pas avoir de références NULL. Vous devez toujours pouvoir supposer qu'une référence est connectée à un élément de stockage légitime.

  • Une fois qu'une référence est initialisée à un objet, elle ne peut pas être modifiée pour faire référence à un autre objet. Les pointeurs peuvent être pointés vers un autre objet à tout moment.

  • Une référence doit être initialisée lors de sa création. Les pointeurs peuvent être initialisés à tout moment.

Création de références en C ++

Considérez un nom de variable comme une étiquette attachée à l'emplacement de la variable en mémoire. Vous pouvez alors considérer une référence comme une deuxième étiquette attachée à cet emplacement mémoire. Par conséquent, vous pouvez accéder au contenu de la variable via le nom de la variable d'origine ou la référence. Par exemple, supposons que nous ayons l'exemple suivant -

int i = 17;

Nous pouvons déclarer des variables de référence pour i comme suit.

int& r = i;

Lisez le & dans ces déclarations comme reference. Ainsi, lisez la première déclaration comme "r est une référence entière initialisée à i" et lisez la deuxième déclaration comme "s est une double référence initialisée à d.". L'exemple suivant utilise des références sur int et double -

#include <iostream>
 
using namespace std;
 
int main () {
   // declare simple variables
   int    i;
   double d;
 
   // declare reference variables
   int&    r = i;
   double& s = d;
   
   i = 5;
   cout << "Value of i : " << i << endl;
   cout << "Value of i reference : " << r  << endl;
 
   d = 11.7;
   cout << "Value of d : " << d << endl;
   cout << "Value of d reference : " << s  << endl;
   
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Value of i : 5
Value of i reference : 5
Value of d : 11.7
Value of d reference : 11.7

Les références sont généralement utilisées pour les listes d'arguments de fonction et les valeurs de retour de fonction. Voici donc deux sujets importants liés aux références C ++ qui devraient être clairs pour un programmeur C ++ -

Sr.Non Concept et description
1 Références en tant que paramètres

C ++ prend en charge le passage de références en tant que paramètre de fonction de manière plus sûre que les paramètres.

2 Référence comme valeur de retour

Vous pouvez renvoyer une référence à partir d'une fonction C ++ comme tout autre type de données.

La bibliothèque standard C ++ ne fournit pas un type de date approprié. C ++ hérite des structures et des fonctions pour la manipulation de la date et de l'heure de C. Pour accéder aux fonctions et structures liées à la date et à l'heure, vous devez inclure le fichier d'en-tête <ctime> dans votre programme C ++.

Il existe quatre types liés au temps: clock_t, time_t, size_t, et tm. Les types - clock_t, size_t et time_t sont capables de représenter l'heure et la date du système sous la forme d'une sorte d'entier.

Le type de structure tm contient la date et l'heure sous la forme d'une structure C ayant les éléments suivants -

struct tm {
   int tm_sec;   // seconds of minutes from 0 to 61
   int tm_min;   // minutes of hour from 0 to 59
   int tm_hour;  // hours of day from 0 to 24
   int tm_mday;  // day of month from 1 to 31
   int tm_mon;   // month of year from 0 to 11
   int tm_year;  // year since 1900
   int tm_wday;  // days since sunday
   int tm_yday;  // days since January 1st
   int tm_isdst; // hours of daylight savings time
}

Voici les fonctions importantes que nous utilisons lorsque nous travaillons avec la date et l'heure en C ou C ++. Toutes ces fonctions font partie de la bibliothèque standard C et C ++ et vous pouvez vérifier leur détail en utilisant la référence à la bibliothèque standard C ++ donnée ci-dessous.

Sr.Non Fonction et objectif
1

time_t time(time_t *time);

Cela renvoie l'heure actuelle du système en nombre de secondes écoulées depuis le 1er janvier 1970. Si le système n'a pas d'heure, .1 est renvoyé.

2

char *ctime(const time_t *time);

Cela renvoie un pointeur vers une chaîne de la forme jour mois année heures: minutes: secondes année \ n \ 0 .

3

struct tm *localtime(const time_t *time);

Cela renvoie un pointeur vers le tm structure représentant l'heure locale.

4

clock_t clock(void);

Cela renvoie une valeur qui se rapproche de la durée d'exécution du programme appelant. Une valeur de .1 est renvoyée si l'heure n'est pas disponible.

5

char * asctime ( const struct tm * time );

Cela renvoie un pointeur vers une chaîne contenant les informations stockées dans la structure pointée par l'heure convertie sous la forme: jour mois date heures: minutes: secondes année \ n \ 0

6

struct tm *gmtime(const time_t *time);

Cela renvoie un pointeur sur l'heure sous la forme d'une structure tm. L'heure est représentée en temps universel coordonné (UTC), qui est essentiellement le temps moyen de Greenwich (GMT).

sept

time_t mktime(struct tm *time);

Cela renvoie l'équivalent calendrier-temps de l'heure trouvée dans la structure pointée par l'heure.

8

double difftime ( time_t time2, time_t time1 );

Cette fonction calcule la différence en secondes entre time1 et time2.

9

size_t strftime();

Cette fonction peut être utilisée pour formater la date et l'heure dans un format spécifique.

Date et heure actuelles

Supposons que vous souhaitiez récupérer la date et l'heure actuelles du système, sous forme d'heure locale ou de temps universel coordonné (UTC). Voici l'exemple pour obtenir le même résultat -

#include <iostream>
#include <ctime>

using namespace std;

int main() {
   // current date/time based on current system
   time_t now = time(0);
   
   // convert now to string form
   char* dt = ctime(&now);

   cout << "The local date and time is: " << dt << endl;

   // convert now to tm struct for UTC
   tm *gmtm = gmtime(&now);
   dt = asctime(gmtm);
   cout << "The UTC date and time is:"<< dt << endl;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

The local date and time is: Sat Jan  8 20:07:41 2011

The UTC date and time is:Sun Jan  9 03:07:41 2011

Formater l'heure à l'aide de struct tm

le tmLa structure est très importante lorsque vous travaillez avec la date et l'heure en C ou C ++. Cette structure contient la date et l'heure sous la forme d'une structure C comme mentionné ci-dessus. La plupart du temps, les fonctions liées utilisent la structure tm. Voici un exemple qui utilise diverses fonctions liées à la date et à l'heure et la structure tm -

En utilisant la structure dans ce chapitre, je suppose que vous avez une compréhension de base de la structure C et comment accéder aux membres de la structure à l'aide de la flèche -> opérateur.

#include <iostream>
#include <ctime>

using namespace std;

int main() {
   // current date/time based on current system
   time_t now = time(0);

   cout << "Number of sec since January 1,1970 is:: " << now << endl;

   tm *ltm = localtime(&now);

   // print various components of tm structure.
   cout << "Year:" << 1900 + ltm->tm_year<<endl;
   cout << "Month: "<< 1 + ltm->tm_mon<< endl;
   cout << "Day: "<< ltm->tm_mday << endl;
   cout << "Time: "<< 5+ltm->tm_hour << ":";
   cout << 30+ltm->tm_min << ":";
   cout << ltm->tm_sec << endl;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Number of sec since January 1,1970 is:: 1588485717
Year:2020
Month: 5
Day: 3
Time: 11:31:57

Les bibliothèques standard C ++ fournissent un ensemble complet de capacités d'entrée / sortie que nous verrons dans les chapitres suivants. Ce chapitre abordera les opérations d'E / S les plus basiques et les plus courantes requises pour la programmation C ++.

Les E / S C ++ se produisent dans les flux, qui sont des séquences d'octets. Si des octets circulent d'un périphérique comme un clavier, un lecteur de disque ou une connexion réseau, etc. vers la mémoire principale, cela s'appelleinput operation et si des octets circulent de la mémoire principale vers un périphérique comme un écran d'affichage, une imprimante, un lecteur de disque ou une connexion réseau, etc., cela s'appelle output operation.

Fichiers d'en-tête de bibliothèque d'E / S

Les fichiers d'en-tête suivants sont importants pour les programmes C ++ -

Sr.Non Fichier d'en-tête, fonction et description
1

<iostream>

Ce fichier définit le cin, cout, cerr et clog objets, qui correspondent respectivement au flux d'entrée standard, au flux de sortie standard, au flux d'erreur standard non tamponné et au flux d'erreur standard tamponné.

2

<iomanip>

Ce fichier déclare des services utiles pour effectuer des E / S formatées avec des manipulateurs de flux paramétrés, tels que setw et setprecision.

3

<fstream>

Ce fichier déclare des services pour le traitement de fichiers contrôlé par l'utilisateur. Nous en discuterons en détail dans le chapitre relatif aux fichiers et aux flux.

Le flux de sortie standard (cout)

L'objet prédéfini cout est une instance de ostreamclasse. On dit que l'objet cout est "connecté" au périphérique de sortie standard, qui est généralement l'écran d'affichage. lecout est utilisé en conjonction avec l'opérateur d'insertion de flux, qui s'écrit << qui sont deux signes de moins que comme illustré dans l'exemple suivant.

#include <iostream>
 
using namespace std;
 
int main() {
   char str[] = "Hello C++";
 
   cout << "Value of str is : " << str << endl;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Value of str is : Hello C++

Le compilateur C ++ détermine également le type de données de la variable à générer et sélectionne l'opérateur d'insertion de flux approprié pour afficher la valeur. L'opérateur << est surchargé pour générer des éléments de données de types intégrés integer, float, double, strings et pointer values.

L'opérateur d'insertion << peut être utilisé plus d'une fois dans une seule instruction comme indiqué ci-dessus et endl est utilisé pour ajouter une nouvelle ligne à la fin de la ligne.

Le flux d'entrée standard (cin)

L'objet prédéfini cin est une instance de istreamclasse. On dit que l'objet cin est attaché au périphérique d'entrée standard, qui est généralement le clavier. lecin est utilisé en conjonction avec l'opérateur d'extraction de flux, qui s'écrit >> qui sont deux signes supérieurs à, comme illustré dans l'exemple suivant.

#include <iostream>
 
using namespace std;
 
int main() {
   char name[50];
 
   cout << "Please enter your name: ";
   cin >> name;
   cout << "Your name is: " << name << endl;
 
}

Lorsque le code ci-dessus est compilé et exécuté, il vous demandera d'entrer un nom. Vous entrez une valeur, puis appuyez sur Entrée pour voir le résultat suivant -

Please enter your name: cplusplus
Your name is: cplusplus

Le compilateur C ++ détermine également le type de données de la valeur entrée et sélectionne l'opérateur d'extraction de flux approprié pour extraire la valeur et la stocker dans les variables données.

L'opérateur d'extraction de flux >> peut être utilisé plus d'une fois dans une seule instruction. Pour demander plus d'une donnée, vous pouvez utiliser ce qui suit -

cin >> name >> age;

Ce sera équivalent aux deux déclarations suivantes -

cin >> name;
cin >> age;

Le flux d'erreur standard (cerr)

L'objet prédéfini cerr est une instance de ostreamclasse. On dit que l'objet cerr est attaché au dispositif d'erreur standard, qui est également un écran d'affichage mais l'objetcerr n'est pas mis en mémoire tampon et chaque insertion de flux dans cerr fait apparaître immédiatement sa sortie.

le cerr est également utilisé en conjonction avec l'opérateur d'insertion de flux, comme illustré dans l'exemple suivant.

#include <iostream>
 
using namespace std;
 
int main() {
   char str[] = "Unable to read....";
 
   cerr << "Error message : " << str << endl;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Error message : Unable to read....

Le flux de journaux standard (sabotage)

L'objet prédéfini clog est une instance de ostreamclasse. On dit que l'objet de sabot est attaché au dispositif d'erreur standard, qui est également un écran d'affichage mais l'objetclogest tamponné. Cela signifie que chaque insertion à obstruer peut entraîner le maintien de sa sortie dans un tampon jusqu'à ce que le tampon soit rempli ou jusqu'à ce que le tampon soit vidé.

le clog est également utilisé en conjonction avec l'opérateur d'insertion de flux, comme illustré dans l'exemple suivant.

#include <iostream>
 
using namespace std;
 
int main() {
   char str[] = "Unable to read....";
 
   clog << "Error message : " << str << endl;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Error message : Unable to read....

Vous ne pourriez voir aucune différence de cout, de cerr et de sabot avec ces petits exemples, mais lors de l'écriture et de l'exécution de gros programmes, la différence devient évidente. Il est donc recommandé d'afficher les messages d'erreur à l'aide du flux cerr et, lors de l'affichage d'autres messages de journal, le sabotage doit être utilisé.

Les tableaux C / C ++ vous permettent de définir des variables qui combinent plusieurs éléments de données du même type, mais structure est un autre type de données défini par l'utilisateur qui vous permet de combiner des éléments de données de différents types.

Les structures sont utilisées pour représenter un enregistrement, supposons que vous souhaitiez garder une trace de vos livres dans une bibliothèque. Vous souhaiterez peut-être suivre les attributs suivants pour chaque livre -

  • Title
  • Author
  • Subject
  • ID du livre

Définition d'une structure

Pour définir une structure, vous devez utiliser l'instruction struct. L'instruction struct définit un nouveau type de données, avec plus d'un membre, pour votre programme. Le format de l'instruction struct est le suivant -

struct [structure tag] {
   member definition;
   member definition;
   ...
   member definition;
} [one or more structure variables];

le structure tagest facultative et chaque définition de membre est une définition de variable normale, telle que int i; ou float f; ou toute autre définition de variable valide. A la fin de la définition de la structure, avant le point-virgule final, vous pouvez spécifier une ou plusieurs variables de structure mais c'est facultatif. Voici la façon dont vous déclareriez la structure Book -

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;

Accès aux membres de la structure

Pour accéder à n'importe quel membre d'une structure, nous utilisons le member access operator (.). L'opérateur d'accès au membre est codé comme un point entre le nom de la variable de structure et le membre de la structure auquel nous souhaitons accéder. Vous utiliseriezstructmot-clé pour définir des variables de type structure. Voici l'exemple pour expliquer l'utilisation de la structure -

#include <iostream>
#include <cstring>
 
using namespace std;
 
struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main() {
   struct Books Book1;        // Declare Book1 of type Book
   struct Books Book2;        // Declare Book2 of type Book
 
   // book 1 specification
   strcpy( Book1.title, "Learn C++ Programming");
   strcpy( Book1.author, "Chand Miyan"); 
   strcpy( Book1.subject, "C++ Programming");
   Book1.book_id = 6495407;

   // book 2 specification
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Yakit Singha");
   strcpy( Book2.subject, "Telecom");
   Book2.book_id = 6495700;
 
   // Print Book1 info
   cout << "Book 1 title : " << Book1.title <<endl;
   cout << "Book 1 author : " << Book1.author <<endl;
   cout << "Book 1 subject : " << Book1.subject <<endl;
   cout << "Book 1 id : " << Book1.book_id <<endl;

   // Print Book2 info
   cout << "Book 2 title : " << Book2.title <<endl;
   cout << "Book 2 author : " << Book2.author <<endl;
   cout << "Book 2 subject : " << Book2.subject <<endl;
   cout << "Book 2 id : " << Book2.book_id <<endl;

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Book 1 title : Learn C++ Programming
Book 1 author : Chand Miyan
Book 1 subject : C++ Programming
Book 1 id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Yakit Singha
Book 2 subject : Telecom
Book 2 id : 6495700

Structures comme arguments de fonction

Vous pouvez passer une structure en tant qu'argument de fonction de manière très similaire à celle de toute autre variable ou pointeur. Vous accéderiez aux variables de structure de la même manière que vous avez accédé dans l'exemple ci-dessus -

#include <iostream>
#include <cstring>
 
using namespace std;
void printBook( struct Books book );

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main() {
   struct Books Book1;        // Declare Book1 of type Book
   struct Books Book2;        // Declare Book2 of type Book
 
   // book 1 specification
   strcpy( Book1.title, "Learn C++ Programming");
   strcpy( Book1.author, "Chand Miyan"); 
   strcpy( Book1.subject, "C++ Programming");
   Book1.book_id = 6495407;

   // book 2 specification
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Yakit Singha");
   strcpy( Book2.subject, "Telecom");
   Book2.book_id = 6495700;
 
   // Print Book1 info
   printBook( Book1 );

   // Print Book2 info
   printBook( Book2 );

   return 0;
}
void printBook( struct Books book ) {
   cout << "Book title : " << book.title <<endl;
   cout << "Book author : " << book.author <<endl;
   cout << "Book subject : " << book.subject <<endl;
   cout << "Book id : " << book.book_id <<endl;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Book title : Learn C++ Programming
Book author : Chand Miyan
Book subject : C++ Programming
Book id : 6495407
Book title : Telecom Billing
Book author : Yakit Singha
Book subject : Telecom
Book id : 6495700

Pointeurs vers des structures

Vous pouvez définir des pointeurs vers des structures de la même manière que vous définissez le pointeur vers n'importe quelle autre variable comme suit -

struct Books *struct_pointer;

Vous pouvez désormais stocker l'adresse d'une variable de structure dans la variable de pointeur définie ci-dessus. Pour trouver l'adresse d'une variable de structure, placez l'opérateur & avant le nom de la structure comme suit -

struct_pointer = &Book1;

Pour accéder aux membres d'une structure à l'aide d'un pointeur vers cette structure, vous devez utiliser l'opérateur -> comme suit -

struct_pointer->title;

Réécrivons l'exemple ci-dessus en utilisant un pointeur de structure, espérons que cela vous sera facile de comprendre le concept -

#include <iostream>
#include <cstring>
 
using namespace std;
void printBook( struct Books *book );

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
int main() {
   struct Books Book1;        // Declare Book1 of type Book
   struct Books Book2;        // Declare Book2 of type Book
 
   // Book 1 specification
   strcpy( Book1.title, "Learn C++ Programming");
   strcpy( Book1.author, "Chand Miyan"); 
   strcpy( Book1.subject, "C++ Programming");
   Book1.book_id = 6495407;

   // Book 2 specification
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Yakit Singha");
   strcpy( Book2.subject, "Telecom");
   Book2.book_id = 6495700;
 
   // Print Book1 info, passing address of structure
   printBook( &Book1 );

   // Print Book1 info, passing address of structure
   printBook( &Book2 );

   return 0;
}

// This function accept pointer to structure as parameter.
void printBook( struct Books *book ) {
   cout << "Book title : " << book->title <<endl;
   cout << "Book author : " << book->author <<endl;
   cout << "Book subject : " << book->subject <<endl;
   cout << "Book id : " << book->book_id <<endl;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Book title : Learn C++ Programming
Book author : Chand Miyan
Book subject : C++ Programming
Book id : 6495407
Book title : Telecom Billing
Book author : Yakit Singha
Book subject : Telecom
Book id : 6495700

Le mot-clé typedef

Il existe un moyen plus simple de définir des structures ou vous pouvez "alias" les types que vous créez. Par exemple -

typedef struct {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} Books;

Désormais, vous pouvez utiliser Books directement pour définir des variables de type Books sans utiliser le mot clé struct. Voici l'exemple -

Books Book1, Book2;

Vous pouvez utiliser typedef mot-clé pour les non-structs ainsi que les suivants -

typedef long int *pint32;
 
pint32 x, y, z;

x, y et z sont tous des pointeurs vers des entiers longs.

L'objectif principal de la programmation C ++ est d'ajouter une orientation objet au langage de programmation C et les classes sont la caractéristique centrale de C ++ qui prend en charge la programmation orientée objet et sont souvent appelées types définis par l'utilisateur.

Une classe est utilisée pour spécifier la forme d'un objet et combine la représentation des données et les méthodes de manipulation de ces données dans un package soigné. Les données et les fonctions d'une classe sont appelées membres de la classe.

Définitions de classe C ++

Lorsque vous définissez une classe, vous définissez un plan pour un type de données. Cela ne définit en fait aucune donnée, mais définit ce que signifie le nom de la classe, c'est-à-dire en quoi consistera un objet de la classe et quelles opérations peuvent être effectuées sur un tel objet.

Une définition de classe commence par le mot-clé classsuivi du nom de la classe; et le corps de la classe, entouré par une paire d'accolades. Une définition de classe doit être suivie d'un point-virgule ou d'une liste de déclarations. Par exemple, nous avons défini le type de données Box à l'aide du mot-cléclass comme suit -

class Box {
   public:
      double length;   // Length of a box
      double breadth;  // Breadth of a box
      double height;   // Height of a box
};

Le mot clé publicdétermine les attributs d'accès des membres de la classe qui la suit. Un membre public est accessible depuis l'extérieur de la classe n'importe où dans la portée de l'objet de classe. Vous pouvez également spécifier les membres d'une classe commeprivate ou protected dont nous discuterons dans une sous-section.

Définir des objets C ++

Une classe fournit les plans des objets, donc fondamentalement un objet est créé à partir d'une classe. Nous déclarons les objets d'une classe avec exactement le même type de déclaration que nous déclarons des variables de types de base. Les instructions suivantes déclarent deux objets de la classe Box -

Box Box1;          // Declare Box1 of type Box
Box Box2;          // Declare Box2 of type Box

Les deux objets Box1 et Box2 auront leur propre copie des données membres.

Accès aux données membres

Les membres de données publiques des objets d'une classe sont accessibles à l'aide de l'opérateur d'accès direct aux membres (.). Essayons l'exemple suivant pour clarifier les choses -

#include <iostream>

using namespace std;

class Box {
   public:
      double length;   // Length of a box
      double breadth;  // Breadth of a box
      double height;   // Height of a box
};

int main() {
   Box Box1;        // Declare Box1 of type Box
   Box Box2;        // Declare Box2 of type Box
   double volume = 0.0;     // Store the volume of a box here
 
   // box 1 specification
   Box1.height = 5.0; 
   Box1.length = 6.0; 
   Box1.breadth = 7.0;

   // box 2 specification
   Box2.height = 10.0;
   Box2.length = 12.0;
   Box2.breadth = 13.0;
   
   // volume of box 1
   volume = Box1.height * Box1.length * Box1.breadth;
   cout << "Volume of Box1 : " << volume <<endl;

   // volume of box 2
   volume = Box2.height * Box2.length * Box2.breadth;
   cout << "Volume of Box2 : " << volume <<endl;
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Volume of Box1 : 210
Volume of Box2 : 1560

Il est important de noter que les membres privés et protégés ne sont pas accessibles directement à l'aide de l'opérateur d'accès direct aux membres (.). Nous découvrirons comment accéder aux membres privés et protégés.

Classes et objets en détail

Jusqu'à présent, vous avez une idée très basique des classes et des objets C ++. Il existe d'autres concepts intéressants liés aux classes et objets C ++ que nous discuterons dans diverses sous-sections répertoriées ci-dessous -

Sr.Non Concept et description
1 Fonctions des membres de classe

Une fonction membre d'une classe est une fonction qui a sa définition ou son prototype dans la définition de classe comme toute autre variable.

2 Modificateurs d'accès aux classes

Un membre de classe peut être défini comme public, privé ou protégé. Par défaut, les membres seraient considérés comme privés.

3 Constructeur et destructeur

Un constructeur de classe est une fonction spéciale dans une classe qui est appelée lorsqu'un nouvel objet de la classe est créé. Un destructeur est également une fonction spéciale qui est appelée lorsque l'objet créé est supprimé.

4 Copier le constructeur

Le constructeur de copie est un constructeur qui crée un objet en l'initialisant avec un objet de la même classe, qui a été créé précédemment.

5 Fonctions d'ami

UNE friend function est autorisé à accéder pleinement aux membres privés et protégés d'une classe.

6 Fonctions en ligne

Avec une fonction en ligne, le compilateur essaie de développer le code dans le corps de la fonction au lieu d'un appel à la fonction.

sept ce pointeur

Chaque objet a un pointeur spécial this qui pointe vers l'objet lui-même.

8 Pointeur vers les classes C ++

Un pointeur vers une classe se fait exactement de la même manière qu'un pointeur vers une structure. En fait, une classe n'est en réalité qu'une structure contenant des fonctions.

9 Membres statiques d'une classe

Les membres de données et les membres de fonction d'une classe peuvent être déclarés comme statiques.

L'un des concepts les plus importants de la programmation orientée objet est celui de l'héritage. L'héritage nous permet de définir une classe en termes d'une autre classe, ce qui facilite la création et la maintenance d'une application. Cela offre également la possibilité de réutiliser la fonctionnalité de code et un temps de mise en œuvre rapide.

Lors de la création d'une classe, au lieu d'écrire des membres de données et des fonctions membres complètement nouveaux, le programmeur peut désigner que la nouvelle classe doit hériter des membres d'une classe existante. Cette classe existante s'appelle lebase class, et la nouvelle classe est appelée derived classe.

L'idée d'héritage met en œuvre le is arelation. Par exemple, le mammifère IS-A animal, le chien IS-A mammifère donc le chien IS-A également et ainsi de suite.

Classes de base et dérivées

Une classe peut être dérivée de plusieurs classes, ce qui signifie qu'elle peut hériter des données et des fonctions de plusieurs classes de base. Pour définir une classe dérivée, nous utilisons une liste de dérivation de classe pour spécifier la ou les classes de base. Une liste de dérivation de classe nomme une ou plusieurs classes de base et a la forme -

class derived-class: access-specifier base-class

Où spécificateur d'accès est l'un des public, protected, ou private, et base-class est le nom d'une classe précédemment définie. Si le spécificateur d'accès n'est pas utilisé, il est privé par défaut.

Considérez une classe de base Shape et sa classe dérivée Rectangle comme suit -

#include <iostream>
 
using namespace std;

// Base class
class Shape {
   public:
      void setWidth(int w) {
         width = w;
      }
      void setHeight(int h) {
         height = h;
      }
      
   protected:
      int width;
      int height;
};

// Derived class
class Rectangle: public Shape {
   public:
      int getArea() { 
         return (width * height); 
      }
};

int main(void) {
   Rectangle Rect;
 
   Rect.setWidth(5);
   Rect.setHeight(7);

   // Print the area of the object.
   cout << "Total area: " << Rect.getArea() << endl;

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Total area: 35

Contrôle d'accès et héritage

Une classe dérivée peut accéder à tous les membres non privés de sa classe de base. Ainsi, les membres de la classe de base qui ne devraient pas être accessibles aux fonctions membres des classes dérivées doivent être déclarés privés dans la classe de base.

Nous pouvons résumer les différents types d'accès selon - qui peut y accéder de la manière suivante -

Accès Publique protégé privé
Même classe Oui Oui Oui
Classes dérivées Oui Oui non
Hors cours Oui non non

Une classe dérivée hérite de toutes les méthodes de classe de base avec les exceptions suivantes -

  • Constructeurs, destructeurs et constructeurs de copie de la classe de base.
  • Opérateurs surchargés de la classe de base.
  • Les fonctions friend de la classe de base.

Type d'héritage

Lors de la dérivation d'une classe à partir d'une classe de base, la classe de base peut être héritée via public, protected ou privatehéritage. Le type d'héritage est spécifié par le spécificateur d'accès comme expliqué ci-dessus.

Nous utilisons à peine protected ou private héritage, mais publicl'héritage est couramment utilisé. Lors de l'utilisation de différents types d'héritage, les règles suivantes sont appliquées -

  • Public Inheritance - Lors de la dérivation d'une classe à partir d'un public classe de base, public les membres de la classe de base deviennent public membres de la classe dérivée et protected les membres de la classe de base deviennent protectedmembres de la classe dérivée. Une classe de baseprivate les membres ne sont jamais accessibles directement à partir d'une classe dérivée, mais sont accessibles via des appels au public et protected membres de la classe de base.

  • Protected Inheritance - En dérivant d'un protected classe de base, public et protected les membres de la classe de base deviennent protected membres de la classe dérivée.

  • Private Inheritance - En dérivant d'un private classe de base, public et protected les membres de la classe de base deviennent private membres de la classe dérivée.

Héritage multiple

Une classe C ++ peut hériter des membres de plus d'une classe et voici la syntaxe étendue -

class derived-class: access baseA, access baseB....

Où l'accès est l'un des public, protected, ou privateet serait donné pour chaque classe de base et ils seront séparés par une virgule comme indiqué ci-dessus. Essayons l'exemple suivant -

#include <iostream>
 
using namespace std;

// Base class Shape
class Shape {
   public:
      void setWidth(int w) {
         width = w;
      }
      void setHeight(int h) {
         height = h;
      }
      
   protected:
      int width;
      int height;
};

// Base class PaintCost
class PaintCost {
   public:
      int getCost(int area) {
         return area * 70;
      }
};

// Derived class
class Rectangle: public Shape, public PaintCost {
   public:
      int getArea() {
         return (width * height); 
      }
};

int main(void) {
   Rectangle Rect;
   int area;
 
   Rect.setWidth(5);
   Rect.setHeight(7);

   area = Rect.getArea();
   
   // Print the area of the object.
   cout << "Total area: " << Rect.getArea() << endl;

   // Print the total cost of painting
   cout << "Total paint cost: $" << Rect.getCost(area) << endl;

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Total area: 35
Total paint cost: $2450

C ++ vous permet de spécifier plus d'une définition pour un function nom ou un operator dans la même portée, qui s'appelle function overloading et operator overloading respectivement.

Une déclaration surchargée est une déclaration qui est déclarée avec le même nom qu'une déclaration précédemment déclarée dans la même portée, sauf que les deux déclarations ont des arguments différents et une définition (implémentation) évidemment différente.

Lorsque vous appelez un surchargé function ou operator, le compilateur détermine la définition la plus appropriée à utiliser, en comparant les types d'argument que vous avez utilisés pour appeler la fonction ou l'opérateur avec les types de paramètres spécifiés dans les définitions. Le processus de sélection de la fonction ou de l'opérateur surchargé le plus approprié est appeléoverload resolution.

Surcharge de fonction en C ++

Vous pouvez avoir plusieurs définitions pour le même nom de fonction dans la même portée. La définition de la fonction doit différer les unes des autres par les types et / ou le nombre d'arguments dans la liste d'arguments. Vous ne pouvez pas surcharger les déclarations de fonction qui diffèrent uniquement par le type de retour.

Voici l'exemple où la même fonction print() est utilisé pour imprimer différents types de données -

#include <iostream>
using namespace std;
 
class printData {
   public:
      void print(int i) {
        cout << "Printing int: " << i << endl;
      }
      void print(double  f) {
        cout << "Printing float: " << f << endl;
      }
      void print(char* c) {
        cout << "Printing character: " << c << endl;
      }
};

int main(void) {
   printData pd;
 
   // Call print to print integer
   pd.print(5);
   
   // Call print to print float
   pd.print(500.263);
   
   // Call print to print character
   pd.print("Hello C++");
 
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Printing int: 5
Printing float: 500.263
Printing character: Hello C++

Surcharge des opérateurs en C ++

Vous pouvez redéfinir ou surcharger la plupart des opérateurs intégrés disponibles en C ++. Ainsi, un programmeur peut également utiliser des opérateurs avec des types définis par l'utilisateur.

Les opérateurs surchargés sont des fonctions avec des noms spéciaux: le mot-clé "opérateur" suivi du symbole de l'opérateur en cours de définition. Comme toute autre fonction, un opérateur surchargé a un type de retour et une liste de paramètres.

Box operator+(const Box&);

déclare l'opérateur d'addition qui peut être utilisé pour adddeux objets Box et renvoie l'objet Box final. La plupart des opérateurs surchargés peuvent être définis comme des fonctions non membres ordinaires ou comme des fonctions membres de classe. Dans le cas où nous définissons la fonction ci-dessus comme une fonction non membre d'une classe, nous devrions alors passer deux arguments pour chaque opérande comme suit -

Box operator+(const Box&, const Box&);

Voici l'exemple pour montrer le concept d'opérateur en surcharge à l'aide d'une fonction membre. Ici un objet est passé en argument dont les propriétés seront accessibles à l'aide de cet objet, l'objet qui appellera cet opérateur est accessible viathis opérateur comme expliqué ci-dessous -

#include <iostream>
using namespace std;

class Box {
   public:
      double getVolume(void) {
         return length * breadth * height;
      }
      void setLength( double len ) {
         length = len;
      }
      void setBreadth( double bre ) {
         breadth = bre;
      }
      void setHeight( double hei ) {
         height = hei;
      }
      
      // Overload + operator to add two Box objects.
      Box operator+(const Box& b) {
         Box box;
         box.length = this->length + b.length;
         box.breadth = this->breadth + b.breadth;
         box.height = this->height + b.height;
         return box;
      }
      
   private:
      double length;      // Length of a box
      double breadth;     // Breadth of a box
      double height;      // Height of a box
};

// Main function for the program
int main() {
   Box Box1;                // Declare Box1 of type Box
   Box Box2;                // Declare Box2 of type Box
   Box Box3;                // Declare Box3 of type Box
   double volume = 0.0;     // Store the volume of a box here
 
   // box 1 specification
   Box1.setLength(6.0); 
   Box1.setBreadth(7.0); 
   Box1.setHeight(5.0);
 
   // box 2 specification
   Box2.setLength(12.0); 
   Box2.setBreadth(13.0); 
   Box2.setHeight(10.0);
 
   // volume of box 1
   volume = Box1.getVolume();
   cout << "Volume of Box1 : " << volume <<endl;
 
   // volume of box 2
   volume = Box2.getVolume();
   cout << "Volume of Box2 : " << volume <<endl;

   // Add two object as follows:
   Box3 = Box1 + Box2;

   // volume of box 3
   volume = Box3.getVolume();
   cout << "Volume of Box3 : " << volume <<endl;

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400

Opérateurs surchargeables / non surchargeables

Voici la liste des opérateurs qui peuvent être surchargés -

+ - * / % ^
& | ~ ! , =
< > <= > = ++ -
<< >> == ! = && ||
+ = - = / = % = ^ = & =
| = * = << = >> = [] ()
-> -> * Nouveau Nouveau [] effacer effacer []

Voici la liste des opérateurs, qui ne peuvent pas être surchargés -

:: . * . ?:

Exemples de surcharge d'opérateur

Voici divers exemples de surcharge d'opérateurs pour vous aider à comprendre le concept.

Sr.Non Opérateurs et exemple
1 Surcharge des opérateurs unaires
2 Surcharge des opérateurs binaires
3 Surcharge des opérateurs relationnels
4 Surcharge des opérateurs d'entrée / sortie
5 ++ et - Surcharge des opérateurs
6 Surcharge des opérateurs d'affectation
sept Appel de fonction () Surcharge de l'opérateur
8 Souscription [] Surcharge de l'opérateur
9 Opérateur d'accès aux membres de la classe -> Surcharge

Le mot polymorphismsignifie avoir plusieurs formes. En règle générale, le polymorphisme se produit lorsqu'il existe une hiérarchie de classes et qu'elles sont liées par héritage.

Le polymorphisme C ++ signifie qu'un appel à une fonction membre entraînera l'exécution d'une fonction différente en fonction du type d'objet qui appelle la fonction.

Prenons l'exemple suivant où une classe de base a été dérivée par deux autres classes -

#include <iostream> 
using namespace std;
 
class Shape {
   protected:
      int width, height;
      
   public:
      Shape( int a = 0, int b = 0){
         width = a;
         height = b;
      }
      int area() {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};
class Rectangle: public Shape {
   public:
      Rectangle( int a = 0, int b = 0):Shape(a, b) { }
      
      int area () { 
         cout << "Rectangle class area :" <<endl;
         return (width * height); 
      }
};

class Triangle: public Shape {
   public:
      Triangle( int a = 0, int b = 0):Shape(a, b) { }
      
      int area () { 
         cout << "Triangle class area :" <<endl;
         return (width * height / 2); 
      }
};

// Main function for the program
int main() {
   Shape *shape;
   Rectangle rec(10,7);
   Triangle  tri(10,5);

   // store the address of Rectangle
   shape = &rec;
   
   // call rectangle area.
   shape->area();

   // store the address of Triangle
   shape = &tri;
   
   // call triangle area.
   shape->area();
   
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Parent class area :
Parent class area :

La raison de la sortie incorrecte est que l'appel de la fonction area () est défini une fois par le compilateur comme version définie dans la classe de base. C'est appeléstatic resolution de l'appel de fonction, ou static linkage- l'appel de fonction est fixé avant l'exécution du programme. Ceci est aussi parfois appeléearly binding car la fonction area () est définie lors de la compilation du programme.

Mais maintenant, faisons une légère modification dans notre programme et précédons la déclaration de area () dans la classe Shape avec le mot-clé virtual pour que ça ressemble à ça -

class Shape {
   protected:
      int width, height;
      
   public:
      Shape( int a = 0, int b = 0) {
         width = a;
         height = b;
      }
      virtual int area() {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};

Après cette légère modification, lorsque l'exemple de code précédent est compilé et exécuté, il produit le résultat suivant -

Rectangle class area
Triangle class area

Cette fois, le compilateur regarde le contenu du pointeur au lieu de son type. Par conséquent, puisque les adresses des objets des classes tri et rec sont stockées sous forme *, la fonction area () respective est appelée.

Comme vous pouvez le voir, chacune des classes enfants a une implémentation distincte pour la fonction area (). C'est ainsipolymorphismest généralement utilisé. Vous avez différentes classes avec une fonction du même nom, et même les mêmes paramètres, mais avec des implémentations différentes.

Fonction virtuelle

UNE virtual function est une fonction dans une classe de base qui est déclarée à l'aide du mot-clé virtual. La définition dans une classe de base d'une fonction virtuelle, avec une autre version dans une classe dérivée, signale au compilateur que nous ne voulons pas de liaison statique pour cette fonction.

Ce que nous voulons, c'est que la sélection de la fonction à appeler à un point donné du programme soit basée sur le type d'objet pour lequel elle est appelée. Ce type d'opération est appelédynamic linkage, ou late binding.

Fonctions virtuelles pures

Il est possible que vous souhaitiez inclure une fonction virtuelle dans une classe de base afin qu'elle puisse être redéfinie dans une classe dérivée pour s'adapter aux objets de cette classe, mais qu'il n'y ait pas de définition significative que vous pourriez donner pour la fonction dans la classe de base .

Nous pouvons changer la fonction virtuelle area () dans la classe de base comme suit -

class Shape {
   protected:
      int width, height;

   public:
      Shape(int a = 0, int b = 0) {
         width = a;
         height = b;
      }
      
      // pure virtual function
      virtual int area() = 0;
};

Le = 0 indique au compilateur que la fonction n'a pas de corps et que la fonction virtuelle ci-dessus sera appelée pure virtual function.

L'abstraction des données se réfère à la fourniture uniquement des informations essentielles au monde extérieur et au masquage de leurs détails d'arrière-plan, c'est-à-dire pour représenter les informations nécessaires dans le programme sans présenter les détails.

L'abstraction des données est une technique de programmation (et de conception) qui repose sur la séparation de l'interface et de la mise en œuvre.

Prenons un exemple réel de téléviseur, que vous pouvez allumer et éteindre, changer de chaîne, régler le volume et ajouter des composants externes tels que des haut-parleurs, des magnétoscopes et des lecteurs DVD, MAIS vous ne connaissez pas ses détails internes, que c'est-à-dire que vous ne savez pas comment il reçoit les signaux hertziens ou via un câble, comment il les traduit et les affiche enfin à l'écran.

Ainsi, nous pouvons dire qu'un téléviseur sépare clairement son implémentation interne de son interface externe et que vous pouvez jouer avec ses interfaces comme le bouton d'alimentation, le changeur de canal et le contrôle du volume sans avoir aucune connaissance de ses composants internes.

En C ++, les classes fournissent un excellent niveau de data abstraction. Ils fournissent suffisamment de méthodes publiques au monde extérieur pour jouer avec la fonctionnalité de l'objet et pour manipuler les données de l'objet, c'est-à-dire l'état sans vraiment savoir comment la classe a été implémentée en interne.

Par exemple, votre programme peut appeler le sort()sans savoir quel algorithme la fonction utilise réellement pour trier les valeurs données. En fait, l'implémentation sous-jacente de la fonctionnalité de tri peut changer entre les versions de la bibliothèque, et tant que l'interface reste la même, votre appel de fonction fonctionnera toujours.

En C ++, nous utilisons classespour définir nos propres types de données abstraits (ADT). Vous pouvez utiliser lecout objet de classe ostream pour diffuser des données vers une sortie standard comme celle-ci -

#include <iostream>
using namespace std;

int main() {
   cout << "Hello C++" <<endl;
   return 0;
}

Ici, vous n'avez pas besoin de comprendre comment coutaffiche le texte sur l'écran de l'utilisateur. Vous devez uniquement connaître l'interface publique et l'implémentation sous-jacente de «cout» est libre de changer.

Les étiquettes d'accès appliquent l'abstraction

En C ++, nous utilisons des étiquettes d'accès pour définir l'interface abstraite de la classe. Une classe peut contenir zéro ou plusieurs étiquettes d'accès -

  • Les membres définis avec un label public sont accessibles à toutes les parties du programme. La vue d'abstraction de données d'un type est définie par ses membres publics.

  • Les membres définis avec une étiquette privée ne sont pas accessibles au code qui utilise la classe. Les sections privées masquent l'implémentation du code qui utilise le type.

Il n'y a aucune restriction sur la fréquence d'apparition d'une étiquette d'accès. Chaque étiquette d'accès spécifie le niveau d'accès des définitions de membre suivantes. Le niveau d'accès spécifié reste en vigueur jusqu'à ce que la prochaine étiquette d'accès soit rencontrée ou que l'accolade droite de fermeture du corps de classe soit vue.

Avantages de l'abstraction des données

L'abstraction des données offre deux avantages importants -

  • Les éléments internes de la classe sont protégés contre les erreurs de niveau utilisateur par inadvertance, qui pourraient corrompre l'état de l'objet.

  • L'implémentation de classe peut évoluer au fil du temps en réponse à des exigences changeantes ou à des rapports de bogue sans nécessiter de changement de code au niveau de l'utilisateur.

En définissant les membres de données uniquement dans la section privée de la classe, l'auteur de la classe est libre d'apporter des modifications aux données. Si l'implémentation change, seul le code de classe doit être examiné pour voir quel effet le changement peut avoir. Si les données sont publiques, toute fonction qui accède directement aux données membres de l'ancienne représentation peut être interrompue.

Exemple d'abstraction de données

Tout programme C ++ dans lequel vous implémentez une classe avec des membres publics et privés est un exemple d'abstraction de données. Prenons l'exemple suivant -

#include <iostream>
using namespace std;

class Adder {
   public:
      // constructor
      Adder(int i = 0) {
         total = i;
      }
      
      // interface to outside world
      void addNum(int number) {
         total += number;
      }
      
      // interface to outside world
      int getTotal() {
         return total;
      };
      
   private:
      // hidden data from outside world
      int total;
};

int main() {
   Adder a;
   
   a.addNum(10);
   a.addNum(20);
   a.addNum(30);

   cout << "Total " << a.getTotal() <<endl;
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Total 60

La classe ci-dessus ajoute les nombres ensemble et renvoie la somme. Les membres du public -addNum et getTotalsont les interfaces avec le monde extérieur et un utilisateur a besoin de les connaître pour utiliser la classe. Le membre privétotal est quelque chose que l'utilisateur n'a pas besoin de connaître, mais qui est nécessaire pour que la classe fonctionne correctement.

Conception de la stratégie

L'abstraction sépare le code en interface et implémentation. Ainsi, lors de la conception de votre composant, vous devez garder l'interface indépendante de l'implémentation de sorte que si vous changez l'implémentation sous-jacente, l'interface reste intacte.

Dans ce cas, quels que soient les programmes utilisant ces interfaces, ils ne seraient pas affectés et auraient juste besoin d'une recompilation avec la dernière implémentation.

Tous les programmes C ++ sont composés des deux éléments fondamentaux suivants -

  • Program statements (code) - C'est la partie d'un programme qui effectue des actions et elles sont appelées fonctions.

  • Program data - Les données sont les informations du programme qui sont affectées par les fonctions du programme.

L'encapsulation est un concept de programmation orientée objet qui lie les données et les fonctions qui manipulent les données, et qui les protège des interférences extérieures et des abus. L'encapsulation des données a conduit à l'important concept POO dedata hiding.

Data encapsulation est un mécanisme de regroupement des données et des fonctions qui les utilisent et data abstraction est un mécanisme permettant d'exposer uniquement les interfaces et de masquer les détails d'implémentation à l'utilisateur.

C ++ prend en charge les propriétés d'encapsulation et de masquage des données via la création de types définis par l'utilisateur, appelés classes. Nous avons déjà étudié qu'une classe peut contenirprivate, protected et publicmembres. Par défaut, tous les éléments définis dans une classe sont privés. Par exemple -

class Box {
   public:
      double getVolume(void) {
         return length * breadth * height;
      }

   private:
      double length;      // Length of a box
      double breadth;     // Breadth of a box
      double height;      // Height of a box
};

Les variables longueur, largeur et hauteur sont private. Cela signifie qu'ils ne sont accessibles que par les autres membres de la classe Box, et non par aucune autre partie de votre programme. C'est une manière dont l'encapsulation est réalisée.

Pour faire des parties d'une classe public (c'est-à-dire accessibles à d'autres parties de votre programme), vous devez les déclarer après publicmot-clé. Toutes les variables ou fonctions définies après le spécificateur public sont accessibles par toutes les autres fonctions de votre programme.

Faire d'une classe l'ami d'une autre expose les détails de l'implémentation et réduit l'encapsulation. L'idéal est de garder autant de détails de chaque classe cachés que possible à toutes les autres classes.

Exemple d'encapsulation de données

Tout programme C ++ dans lequel vous implémentez une classe avec des membres publics et privés est un exemple d'encapsulation et d'abstraction de données. Prenons l'exemple suivant -

#include <iostream>
using namespace std;

class Adder {
   public:
      // constructor
      Adder(int i = 0) {
         total = i;
      }
      
      // interface to outside world
      void addNum(int number) {
         total += number;
      }
      
      // interface to outside world
      int getTotal() {
         return total;
      };
   
   private:
      // hidden data from outside world
      int total;
};

int main() {
   Adder a;
   
   a.addNum(10);
   a.addNum(20);
   a.addNum(30);

   cout << "Total " << a.getTotal() <<endl;
   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Total 60

La classe ci-dessus ajoute les nombres ensemble et renvoie la somme. Les membres du publicaddNum et getTotal sont les interfaces avec le monde extérieur et un utilisateur a besoin de les connaître pour utiliser la classe. Le membre privétotal est quelque chose qui est caché du monde extérieur, mais qui est nécessaire pour que la classe fonctionne correctement.

Conception de la stratégie

La plupart d'entre nous ont appris à rendre les membres de classe privés par défaut à moins que nous n'ayons vraiment besoin de les exposer. C'est juste bienencapsulation.

Cela s'applique le plus souvent aux membres de données, mais s'applique également à tous les membres, y compris les fonctions virtuelles.

Une interface décrit le comportement ou les capacités d'une classe C ++ sans s'engager dans une implémentation particulière de cette classe.

Les interfaces C ++ sont implémentées en utilisant abstract classes et ces classes abstraites ne doivent pas être confondues avec l'abstraction de données qui consiste à séparer les détails d'implémentation des données associées.

Une classe est rendue abstraite en déclarant au moins une de ses fonctions comme pure virtualfonction. Une fonction virtuelle pure est spécifiée en plaçant "= 0" dans sa déclaration comme suit -

class Box {
   public:
      // pure virtual function
      virtual double getVolume() = 0;
      
   private:
      double length;      // Length of a box
      double breadth;     // Breadth of a box
      double height;      // Height of a box
};

Le but d'un abstract class(souvent appelé ABC) consiste à fournir une classe de base appropriée dont d'autres classes peuvent hériter. Les classes abstraites ne peuvent pas être utilisées pour instancier des objets et servent uniquement deinterface. Tenter d'instancier un objet d'une classe abstraite provoque une erreur de compilation.

Ainsi, si une sous-classe d'un ABC doit être instanciée, elle doit implémenter chacune des fonctions virtuelles, ce qui signifie qu'elle prend en charge l'interface déclarée par l'ABC. Le fait de ne pas remplacer une fonction virtuelle pure dans une classe dérivée, puis de tenter d'instancier des objets de cette classe, est une erreur de compilation.

Les classes qui peuvent être utilisées pour instancier des objets sont appelées concrete classes.

Exemple de classe abstraite

Prenons l'exemple suivant où la classe parent fournit une interface à la classe de base pour implémenter une fonction appelée getArea() -

#include <iostream>
 
using namespace std;
 
// Base class
class Shape {
   public:
      // pure virtual function providing interface framework.
      virtual int getArea() = 0;
      void setWidth(int w) {
         width = w;
      }
   
      void setHeight(int h) {
         height = h;
      }
   
   protected:
      int width;
      int height;
};
 
// Derived classes
class Rectangle: public Shape {
   public:
      int getArea() { 
         return (width * height); 
      }
};

class Triangle: public Shape {
   public:
      int getArea() { 
         return (width * height)/2; 
      }
};
 
int main(void) {
   Rectangle Rect;
   Triangle  Tri;
 
   Rect.setWidth(5);
   Rect.setHeight(7);
   
   // Print the area of the object.
   cout << "Total Rectangle area: " << Rect.getArea() << endl;

   Tri.setWidth(5);
   Tri.setHeight(7);
   
   // Print the area of the object.
   cout << "Total Triangle area: " << Tri.getArea() << endl; 

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Total Rectangle area: 35
Total Triangle area: 17

Vous pouvez voir comment une classe abstraite a défini une interface en termes de getArea () et deux autres classes ont implémenté la même fonction mais avec un algorithme différent pour calculer la zone spécifique à la forme.

Conception de la stratégie

Un système orienté objet peut utiliser une classe de base abstraite pour fournir une interface commune et normalisée appropriée pour toutes les applications externes. Ensuite, grâce à l'héritage de cette classe de base abstraite, des classes dérivées sont formées et fonctionnent de manière similaire.

Les capacités (c'est-à-dire les fonctions publiques) offertes par les applications externes sont fournies sous forme de fonctions virtuelles pures dans la classe de base abstraite. Les implémentations de ces fonctions virtuelles pures sont fournies dans les classes dérivées qui correspondent aux types spécifiques de l'application.

Cette architecture permet également d'ajouter facilement de nouvelles applications à un système, même après la définition du système.

Jusqu'à présent, nous avons utilisé le iostream bibliothèque standard, qui fournit cin et cout méthodes de lecture depuis l'entrée standard et d'écriture vers la sortie standard respectivement.

Ce didacticiel vous apprendra à lire et à écrire à partir d'un fichier. Cela nécessite une autre bibliothèque C ++ standard appeléefstream, qui définit trois nouveaux types de données -

Sr.Non Type de données et description
1

ofstream

Ce type de données représente le flux de fichier de sortie et est utilisé pour créer des fichiers et écrire des informations dans des fichiers.

2

ifstream

Ce type de données représente le flux de fichiers d'entrée et est utilisé pour lire les informations des fichiers.

3

fstream

Ce type de données représente le flux de fichiers en général et a les capacités à la fois ofstream et ifstream, ce qui signifie qu'il peut créer des fichiers, écrire des informations dans des fichiers et lire des informations à partir de fichiers.

Pour effectuer le traitement de fichiers en C ++, les fichiers d'en-tête <iostream> et <fstream> doivent être inclus dans votre fichier source C ++.

Ouverture d'un fichier

Un fichier doit être ouvert avant de pouvoir le lire ou y écrire. Soitofstream ou fstreamobjet peut être utilisé pour ouvrir un fichier à écrire. Et l'objet ifstream est utilisé pour ouvrir un fichier à des fins de lecture uniquement.

Voici la syntaxe standard de la fonction open (), qui est membre des objets fstream, ifstream et ofstream.

void open(const char *filename, ios::openmode mode);

Ici, le premier argument spécifie le nom et l'emplacement du fichier à ouvrir et le deuxième argument du open() La fonction membre définit le mode dans lequel le fichier doit être ouvert.

Sr.Non Drapeau de mode et description
1

ios::app

Ajouter le mode. Toutes les sorties dans ce fichier doivent être ajoutées à la fin.

2

ios::ate

Ouvrez un fichier pour la sortie et déplacez le contrôle de lecture / écriture à la fin du fichier.

3

ios::in

Ouvrez un fichier à lire.

4

ios::out

Ouvrez un fichier à écrire.

5

ios::trunc

Si le fichier existe déjà, son contenu sera tronqué avant l'ouverture du fichier.

Vous pouvez combiner deux ou plusieurs de ces valeurs en ORles engager ensemble. Par exemple, si vous souhaitez ouvrir un fichier en mode écriture et le tronquer au cas où il existe déjà, la syntaxe suivante sera:

ofstream outfile;
outfile.open("file.dat", ios::out | ios::trunc );

De la même manière, vous pouvez ouvrir un fichier à des fins de lecture et d'écriture comme suit -

fstream  afile;
afile.open("file.dat", ios::out | ios::in );

Fermer un fichier

Lorsqu'un programme C ++ se termine, il vide automatiquement tous les flux, libère toute la mémoire allouée et ferme tous les fichiers ouverts. Mais il est toujours bon qu'un programmeur ferme tous les fichiers ouverts avant la fin du programme.

Voici la syntaxe standard de la fonction close (), qui est membre des objets fstream, ifstream et ofstream.

void close();

Ecrire dans un fichier

Lors de la programmation C ++, vous écrivez des informations dans un fichier à partir de votre programme à l'aide de l'opérateur d'insertion de flux (<<) tout comme vous utilisez cet opérateur pour afficher les informations à l'écran. La seule différence est que vous utilisez unofstream ou fstream objet au lieu du cout objet.

Lecture à partir d'un fichier

Vous lisez les informations d'un fichier dans votre programme en utilisant l'opérateur d'extraction de flux (>>) tout comme vous utilisez cet opérateur pour saisir des informations à partir du clavier. La seule différence est que vous utilisez unifstream ou fstream objet au lieu du cin objet.

Exemple de lecture et d'écriture

Voici le programme C ++ qui ouvre un fichier en mode lecture et écriture. Après avoir écrit les informations saisies par l'utilisateur dans un fichier nommé afile.dat, le programme lit les informations du fichier et les affiche à l'écran -

#include <fstream>
#include <iostream>
using namespace std;
 
int main () {
   char data[100];

   // open a file in write mode.
   ofstream outfile;
   outfile.open("afile.dat");

   cout << "Writing to the file" << endl;
   cout << "Enter your name: "; 
   cin.getline(data, 100);

   // write inputted data into the file.
   outfile << data << endl;

   cout << "Enter your age: "; 
   cin >> data;
   cin.ignore();
   
   // again write inputted data into the file.
   outfile << data << endl;

   // close the opened file.
   outfile.close();

   // open a file in read mode.
   ifstream infile; 
   infile.open("afile.dat"); 
 
   cout << "Reading from the file" << endl; 
   infile >> data; 

   // write the data at the screen.
   cout << data << endl;
   
   // again read the data from the file and display it.
   infile >> data; 
   cout << data << endl; 

   // close the opened file.
   infile.close();

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit les exemples d'entrée et de sortie suivants -

$./a.out
Writing to the file
Enter your name: Zara
Enter your age: 9
Reading from the file
Zara
9

Les exemples ci-dessus utilisent des fonctions supplémentaires de l'objet cin, comme la fonction getline () pour lire la ligne de l'extérieur et la fonction ignore () pour ignorer les caractères supplémentaires laissés par l'instruction de lecture précédente.

Pointeurs de position de fichier

Tous les deux istream et ostreamfournissent des fonctions membres pour repositionner le pointeur de position de fichier. Ces fonctions membres sontseekg ("seek get") pour istream et seekp ("chercher") pour ostream.

L'argument de seekg et seekp est normalement un entier long. Un deuxième argument peut être spécifié pour indiquer la direction de recherche. La direction de recherche peut êtreios::beg (par défaut) pour le positionnement par rapport au début d'un flux, ios::cur pour le positionnement par rapport à la position actuelle dans un ruisseau ou ios::end pour le positionnement par rapport à la fin d'un flux.

Le pointeur de position de fichier est une valeur entière qui spécifie l'emplacement dans le fichier sous la forme d'un nombre d'octets à partir de l'emplacement de départ du fichier. Quelques exemples de positionnement du pointeur de position de fichier "get" sont -

// position to the nth byte of fileObject (assumes ios::beg)
fileObject.seekg( n );

// position n bytes forward in fileObject
fileObject.seekg( n, ios::cur );

// position n bytes back from end of fileObject
fileObject.seekg( n, ios::end );

// position at end of fileObject
fileObject.seekg( 0, ios::end );

Une exception est un problème qui survient lors de l'exécution d'un programme. Une exception C ++ est une réponse à une circonstance exceptionnelle qui survient lors de l'exécution d'un programme, telle qu'une tentative de division par zéro.

Les exceptions fournissent un moyen de transférer le contrôle d'une partie d'un programme à une autre. La gestion des exceptions C ++ repose sur trois mots-clés:try, catch, et throw.

  • throw- Un programme lève une exception lorsqu'un problème apparaît. Ceci est fait en utilisant unthrow mot-clé.

  • catch- Un programme intercepte une exception avec un gestionnaire d'exceptions à l'endroit dans un programme où vous voulez gérer le problème. lecatch Le mot-clé indique la capture d'une exception.

  • try - Un tryblock identifie un bloc de code pour lequel des exceptions particulières seront activées. Il est suivi d'un ou plusieurs blocs catch.

En supposant qu'un bloc lève une exception, une méthode intercepte une exception en utilisant une combinaison des try et catchmots clés. Un bloc try / catch est placé autour du code qui peut générer une exception. Le code dans un bloc try / catch est appelé code protégé et la syntaxe d'utilisation de try / catch est la suivante:

try {
   // protected code
} catch( ExceptionName e1 ) {
   // catch block
} catch( ExceptionName e2 ) {
   // catch block
} catch( ExceptionName eN ) {
   // catch block
}

Vous pouvez lister plusieurs catch instructions pour attraper différents types d'exceptions au cas où votre try block soulève plus d'une exception dans différentes situations.

Lancer des exceptions

Les exceptions peuvent être lancées n'importe où dans un bloc de code en utilisant throwdéclaration. L'opérande de l'instruction throw détermine un type pour l'exception et peut être n'importe quelle expression et le type du résultat de l'expression détermine le type d'exception levée.

Voici un exemple de levée d'une exception lors de la division par zéro condition -

double division(int a, int b) {
   if( b == 0 ) {
      throw "Division by zero condition!";
   }
   return (a/b);
}

Attraper les exceptions

le catch bloc suivant le tryblock intercepte toute exception. Vous pouvez spécifier le type d'exception que vous souhaitez intercepter et cela est déterminé par la déclaration d'exception qui apparaît entre parenthèses après le mot clé catch.

try {
   // protected code
} catch( ExceptionName e ) {
  // code to handle ExceptionName exception
}

Le code ci-dessus attrapera une exception de ExceptionNametype. Si vous souhaitez spécifier qu'un bloc catch doit gérer tout type d'exception levée dans un bloc try, vous devez mettre une ellipse, ..., entre les parenthèses entourant la déclaration d'exception comme suit -

try {
   // protected code
} catch(...) {
  // code to handle any exception
}

Ce qui suit est un exemple, qui lève une exception de division par zéro et nous l'attrapons dans le bloc catch.

#include <iostream>
using namespace std;

double division(int a, int b) {
   if( b == 0 ) {
      throw "Division by zero condition!";
   }
   return (a/b);
}

int main () {
   int x = 50;
   int y = 0;
   double z = 0;
 
   try {
      z = division(x, y);
      cout << z << endl;
   } catch (const char* msg) {
     cerr << msg << endl;
   }

   return 0;
}

Parce que nous lançons une exception de type const char*, donc tout en interceptant cette exception, nous devons utiliser const char * dans le bloc catch. Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

Division by zero condition!

Exceptions standard C ++

C ++ fournit une liste d'exceptions standard définies dans <exception>que nous pouvons utiliser dans nos programmes. Ceux-ci sont organisés dans une hiérarchie de classes parent-enfant illustrée ci-dessous -

Voici la petite description de chaque exception mentionnée dans la hiérarchie ci-dessus -

Sr.Non Exception et description
1

std::exception

Une exception et une classe parente de toutes les exceptions C ++ standard.

2

std::bad_alloc

Cela peut être jeté par new.

3

std::bad_cast

Cela peut être jeté par dynamic_cast.

4

std::bad_exception

C'est un appareil utile pour gérer les exceptions inattendues dans un programme C ++.

5

std::bad_typeid

Cela peut être jeté par typeid.

6

std::logic_error

Une exception qui peut théoriquement être détectée en lisant le code.

sept

std::domain_error

Il s'agit d'une exception levée lorsqu'un domaine mathématiquement invalide est utilisé.

8

std::invalid_argument

Ceci est renvoyé en raison d'arguments non valides.

9

std::length_error

Ceci est levé quand une trop grande std :: string est créée.

dix

std::out_of_range

Cela peut être lancé par la méthode 'at', par exemple un opérateur std :: vector et std :: bitset <> :: [] ().

11

std::runtime_error

Une exception qui ne peut théoriquement pas être détectée en lisant le code.

12

std::overflow_error

Ceci est émis en cas de dépassement mathématique.

13

std::range_error

Cela se produit lorsque vous essayez de stocker une valeur hors plage.

14

std::underflow_error

Ceci est lancé en cas de dépassement mathématique.

Définir de nouvelles exceptions

Vous pouvez définir vos propres exceptions en héritant et en remplaçant exceptionfonctionnalité de classe. Voici l'exemple, qui montre comment vous pouvez utiliser la classe std :: exception pour implémenter votre propre exception de manière standard -

#include <iostream>
#include <exception>
using namespace std;

struct MyException : public exception {
   const char * what () const throw () {
      return "C++ Exception";
   }
};
 
int main() {
   try {
      throw MyException();
   } catch(MyException& e) {
      std::cout << "MyException caught" << std::endl;
      std::cout << e.what() << std::endl;
   } catch(std::exception& e) {
      //Other errors
   }
}

Cela produirait le résultat suivant -

MyException caught
C++ Exception

Ici, what()est une méthode publique fournie par la classe d'exception et elle a été remplacée par toutes les classes d'exception enfants. Cela renvoie la cause d'une exception.

Une bonne compréhension du fonctionnement réel de la mémoire dynamique en C ++ est essentielle pour devenir un bon programmeur C ++. La mémoire de votre programme C ++ est divisée en deux parties -

  • The stack - Toutes les variables déclarées à l'intérieur de la fonction prendront de la mémoire de la pile.

  • The heap - Il s'agit de la mémoire inutilisée du programme et peut être utilisée pour allouer la mémoire de manière dynamique lors de l'exécution du programme.

Plusieurs fois, vous ne savez pas à l'avance la quantité de mémoire dont vous aurez besoin pour stocker des informations particulières dans une variable définie et la taille de la mémoire requise peut être déterminée au moment de l'exécution.

Vous pouvez allouer de la mémoire au moment de l'exécution dans le tas pour la variable d'un type donné à l'aide d'un opérateur spécial en C ++ qui renvoie l'adresse de l'espace alloué. Cet opérateur s'appellenew opérateur.

Si vous n'avez plus besoin de mémoire allouée dynamiquement, vous pouvez utiliser delete opérateur, qui désalloue la mémoire précédemment allouée par le nouvel opérateur.

nouveaux et supprimer des opérateurs

Il y a la syntaxe générique suivante à utiliser new opérateur pour allouer dynamiquement de la mémoire pour tout type de données.

new data-type;

Ici, data-typepeut être n'importe quel type de données intégré comprenant un tableau ou tout type de données défini par l'utilisateur inclut une classe ou une structure. Commençons par les types de données intégrés. Par exemple, nous pouvons définir un pointeur pour taper double puis demander que la mémoire soit allouée au moment de l'exécution. Nous pouvons le faire en utilisant lenew opérateur avec les instructions suivantes -

double* pvalue  = NULL; // Pointer initialized with null
pvalue  = new double;   // Request memory for the variable

La mémoire n'a peut-être pas été allouée avec succès, si la mémoire libre a été utilisée. Il est donc recommandé de vérifier si le nouvel opérateur renvoie un pointeur NULL et de prendre les mesures appropriées comme ci-dessous -

double* pvalue  = NULL;
if( !(pvalue  = new double )) {
   cout << "Error: out of memory." <<endl;
   exit(1);
}

le malloc()fonction de C, existe toujours en C ++, mais il est recommandé d'éviter d'utiliser la fonction malloc (). Le principal avantage de new par rapport à malloc () est que new n'alloue pas seulement de la mémoire, il construit des objets, ce qui est le but premier de C ++.

À tout moment, lorsque vous sentez qu'une variable qui a été allouée dynamiquement n'est plus nécessaire, vous pouvez libérer la mémoire qu'elle occupe dans le magasin libre avec l'opérateur 'delete' comme suit -

delete pvalue;        // Release memory pointed to by pvalue

Mettons les concepts ci-dessus et formons l'exemple suivant pour montrer comment fonctionnent `` nouveau '' et `` supprimer '' -

#include <iostream>
using namespace std;

int main () {
   double* pvalue  = NULL; // Pointer initialized with null
   pvalue  = new double;   // Request memory for the variable
 
   *pvalue = 29494.99;     // Store value at allocated address
   cout << "Value of pvalue : " << *pvalue << endl;

   delete pvalue;         // free up the memory.

   return 0;
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

Value of pvalue : 29495

Allocation de mémoire dynamique pour les baies

Considérez que vous souhaitez allouer de la mémoire pour un tableau de caractères, c'est-à-dire une chaîne de 20 caractères. En utilisant la même syntaxe que celle que nous avons utilisée ci-dessus, nous pouvons allouer de la mémoire dynamiquement comme indiqué ci-dessous.

char* pvalue  = NULL;         // Pointer initialized with null
pvalue  = new char[20];       // Request memory for the variable

Pour supprimer le tableau que nous venons de créer, l'instruction ressemblerait à ceci:

delete [] pvalue;             // Delete array pointed to by pvalue

En suivant la syntaxe générique similaire du nouvel opérateur, vous pouvez allouer un tableau multidimensionnel comme suit -

double** pvalue  = NULL;      // Pointer initialized with null 
pvalue  = new double [3][4];  // Allocate memory for a 3x4 array

Cependant, la syntaxe pour libérer la mémoire pour un tableau multidimensionnel restera la même que ci-dessus -

delete [] pvalue;            // Delete array pointed to by pvalue

Allocation de mémoire dynamique pour les objets

Les objets ne sont pas différents des types de données simples. Par exemple, considérons le code suivant où nous allons utiliser un tableau d'objets pour clarifier le concept -

#include <iostream>
using namespace std;

class Box {
   public:
      Box() { 
         cout << "Constructor called!" <<endl; 
      }
      ~Box() { 
         cout << "Destructor called!" <<endl; 
      }
};
int main() {
   Box* myBoxArray = new Box[4];
   delete [] myBoxArray; // Delete array

   return 0;
}

Si vous deviez allouer un tableau de quatre objets Box, le constructeur Simple serait appelé quatre fois et de la même manière lors de la suppression de ces objets, le destructeur sera également appelé le même nombre de fois.

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

Constructor called!
Constructor called!
Constructor called!
Constructor called!
Destructor called!
Destructor called!
Destructor called!
Destructor called!

Prenons une situation où nous avons deux personnes du même nom, Zara, dans la même classe. Chaque fois que nous devons les différencier définitivement, nous devrons utiliser des informations supplémentaires avec leur nom, comme la région, s'ils vivent dans une région différente ou le nom de leur mère ou de leur père, etc.

La même situation peut se produire dans vos applications C ++. Par exemple, vous pouvez écrire du code qui a une fonction appelée xyz () et il existe une autre bibliothèque disponible qui a également la même fonction xyz (). Maintenant, le compilateur n'a aucun moyen de savoir à quelle version de la fonction xyz () vous faites référence dans votre code.

UNE namespaceest conçu pour surmonter cette difficulté et est utilisé comme information supplémentaire pour différencier des fonctions similaires, des classes, des variables, etc. avec le même nom disponible dans différentes bibliothèques. À l'aide de l'espace de noms, vous pouvez définir le contexte dans lequel les noms sont définis. En substance, un espace de noms définit une portée.

Définition d'un espace de noms

Une définition d'espace de noms commence par le mot-clé namespace suivi du nom de l'espace de noms comme suit -

namespace namespace_name {
   // code declarations
}

Pour appeler la version activée pour l'espace de noms de la fonction ou de la variable, ajoutez (: :) le nom de l'espace de noms comme suit -

name::code;  // code could be variable or function.

Voyons comment l'espace de noms couvre les entités, y compris la variable et les fonctions -

#include <iostream>
using namespace std;

// first name space
namespace first_space {
   void func() {
      cout << "Inside first_space" << endl;
   }
}

// second name space
namespace second_space {
   void func() {
      cout << "Inside second_space" << endl;
   }
}

int main () {
   // Calls function from first name space.
   first_space::func();
   
   // Calls function from second name space.
   second_space::func(); 

   return 0;
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

Inside first_space
Inside second_space

La directive using

Vous pouvez également éviter l'ajout des espaces de noms avec le using namespacedirectif. Cette directive indique au compilateur que le code suivant utilise des noms dans l'espace de noms spécifié. L'espace de noms est donc impliqué pour le code suivant -

#include <iostream>
using namespace std;

// first name space
namespace first_space {
   void func() {
      cout << "Inside first_space" << endl;
   }
}

// second name space
namespace second_space {
   void func() {
      cout << "Inside second_space" << endl;
   }
}

using namespace first_space;
int main () {
   // This calls function from first name space.
   func();
   
   return 0;
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

Inside first_space

La directive 'using' peut également être utilisée pour faire référence à un élément particulier dans un espace de noms. Par exemple, si la seule partie de l'espace de noms std que vous avez l'intention d'utiliser est cout, vous pouvez vous y référer comme suit:

using std::cout;

Le code suivant peut faire référence à cout sans ajouter au début de l'espace de noms, mais d'autres éléments dans le std l'espace de noms devra toujours être explicite comme suit -

#include <iostream>
using std::cout;

int main () {
   cout << "std::endl is used with std!" << std::endl;
   
   return 0;
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

std::endl is used with std!

Noms introduits dans un usingdirective obéissent aux règles de portée normales. Le nom est visible du point de lausingdirective à la fin du champ d’application dans lequel se trouve la directive. Les entités portant le même nom défini dans une portée externe sont masquées.

Espaces de noms non contigus

Un espace de noms peut être défini en plusieurs parties et donc un espace de noms est constitué de la somme de ses parties définies séparément. Les parties distinctes d'un espace de noms peuvent être réparties sur plusieurs fichiers.

Ainsi, si une partie de l'espace de noms nécessite un nom défini dans un autre fichier, ce nom doit toujours être déclaré. L'écriture d'une définition d'espace de noms suivante définit un nouvel espace de noms ou ajoute de nouveaux éléments à un espace existant -

namespace namespace_name {
   // code declarations
}

Espaces de noms imbriqués

Les espaces de noms peuvent être imbriqués où vous pouvez définir un espace de noms dans un autre espace de noms comme suit -

namespace namespace_name1 {
   // code declarations
   namespace namespace_name2 {
      // code declarations
   }
}

Vous pouvez accéder aux membres de l'espace de noms imbriqué à l'aide des opérateurs de résolution comme suit -

// to access members of namespace_name2
using namespace namespace_name1::namespace_name2;

// to access members of namespace:name1
using namespace namespace_name1;

Dans les instructions ci-dessus, si vous utilisez namespace_name1, les éléments de namespace_name2 seront disponibles dans la portée comme suit -

#include <iostream>
using namespace std;

// first name space
namespace first_space {
   void func() {
      cout << "Inside first_space" << endl;
   }
   
   // second name space
   namespace second_space {
      void func() {
         cout << "Inside second_space" << endl;
      }
   }
}

using namespace first_space::second_space;
int main () {
   // This calls function from second name space.
   func();
   
   return 0;
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

Inside second_space

Les modèles sont la base de la programmation générique, qui implique l'écriture de code d'une manière indépendante de tout type particulier.

Un modèle est un plan ou une formule pour créer une classe générique ou une fonction. Les conteneurs de bibliothèque comme les itérateurs et les algorithmes sont des exemples de programmation générique et ont été développés en utilisant le concept de modèle.

Il existe une seule définition de chaque conteneur, telle que vector, mais nous pouvons définir de nombreux types de vecteurs différents, par exemple, vector <int> ou vector <string>.

Vous pouvez utiliser des modèles pour définir des fonctions ainsi que des classes, voyons comment ils fonctionnent -

Modèle de fonction

La forme générale d'une définition de fonction de modèle est affichée ici -

template <class type> ret-type func-name(parameter list) {
   // body of function
}

Ici, type est un nom d'espace réservé pour un type de données utilisé par la fonction. Ce nom peut être utilisé dans la définition de fonction.

Voici l'exemple d'un modèle de fonction qui renvoie le maximum de deux valeurs -

#include <iostream>
#include <string>

using namespace std;

template <typename T>
inline T const& Max (T const& a, T const& b) { 
   return a < b ? b:a; 
}

int main () {
   int i = 39;
   int j = 20;
   cout << "Max(i, j): " << Max(i, j) << endl; 

   double f1 = 13.5; 
   double f2 = 20.7; 
   cout << "Max(f1, f2): " << Max(f1, f2) << endl; 

   string s1 = "Hello"; 
   string s2 = "World"; 
   cout << "Max(s1, s2): " << Max(s1, s2) << endl; 

   return 0;
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

Max(i, j): 39
Max(f1, f2): 20.7
Max(s1, s2): World

Modèle de classe

Tout comme nous pouvons définir des modèles de fonctions, nous pouvons également définir des modèles de classes. La forme générale d'une déclaration de classe générique est présentée ici -

template <class type> class class-name {
   .
   .
   .
}

Ici, typeest le nom du type d'espace réservé, qui sera spécifié lorsqu'une classe est instanciée. Vous pouvez définir plusieurs types de données génériques à l'aide d'une liste séparée par des virgules.

Voici l'exemple pour définir la classe Stack <> et implémenter des méthodes génériques pour pousser et faire apparaître les éléments de la pile -

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>

using namespace std;

template <class T>
class Stack { 
   private: 
      vector<T> elems;    // elements 

   public: 
      void push(T const&);  // push element 
      void pop();               // pop element 
      T top() const;            // return top element 
      
      bool empty() const {      // return true if empty.
         return elems.empty(); 
      } 
}; 

template <class T>
void Stack<T>::push (T const& elem) { 
   // append copy of passed element 
   elems.push_back(elem);    
} 

template <class T>
void Stack<T>::pop () { 
   if (elems.empty()) { 
      throw out_of_range("Stack<>::pop(): empty stack"); 
   }
   
   // remove last element 
   elems.pop_back();         
} 

template <class T>
T Stack<T>::top () const { 
   if (elems.empty()) { 
      throw out_of_range("Stack<>::top(): empty stack"); 
   }
   
   // return copy of last element 
   return elems.back();      
} 

int main() { 
   try {
      Stack<int>         intStack;  // stack of ints 
      Stack<string> stringStack;    // stack of strings 

      // manipulate int stack 
      intStack.push(7); 
      cout << intStack.top() <<endl; 

      // manipulate string stack 
      stringStack.push("hello"); 
      cout << stringStack.top() << std::endl; 
      stringStack.pop(); 
      stringStack.pop(); 
   } catch (exception const& ex) { 
      cerr << "Exception: " << ex.what() <<endl; 
      return -1;
   } 
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

7
hello
Exception: Stack<>::pop(): empty stack

Les préprocesseurs sont les directives, qui donnent des instructions au compilateur pour prétraiter les informations avant le début de la compilation réelle.

Toutes les directives de préprocesseur commencent par #, et seuls les caractères d'espacement peuvent apparaître avant une directive de préprocesseur sur une ligne. Les directives de préprocesseur ne sont pas des instructions C ++, elles ne se terminent donc pas par un point-virgule (;).

Vous avez déjà vu un #includedirective dans tous les exemples. Cette macro est utilisée pour inclure un fichier d'en-tête dans le fichier source.

Il existe un certain nombre de directives de préprocesseur supportées par C ++ comme #include, #define, #if, #else, #line, etc. Voyons les directives importantes -

Le préprocesseur #define

La directive de préprocesseur #define crée des constantes symboliques. La constante symbolique s'appelle unmacro et la forme générale de la directive est -

#define macro-name replacement-text

Lorsque cette ligne apparaît dans un fichier, toutes les occurrences ultérieures de macro dans ce fichier seront remplacées par replacement-text avant la compilation du programme. Par exemple -

#include <iostream>
using namespace std;

#define PI 3.14159

int main () {
   cout << "Value of PI :" << PI << endl; 

   return 0;
}

Maintenant, faisons le prétraitement de ce code pour voir le résultat en supposant que nous avons le fichier de code source. Alors compilons-le avec l'option -E et redirigeons le résultat vers test.p. Maintenant, si vous vérifiez test.p, il aura beaucoup d'informations et en bas, vous trouverez la valeur remplacée comme suit -

$gcc -E test.cpp > test.p

...
int main () {
   cout << "Value of PI :" << 3.14159 << endl; 
   return 0;
}

Macros fonctionnelles

Vous pouvez utiliser #define pour définir une macro qui prendra l'argument comme suit -

#include <iostream>
using namespace std;

#define MIN(a,b) (((a)<(b)) ? a : b)

int main () {
   int i, j;
   
   i = 100;
   j = 30;
   
   cout <<"The minimum is " << MIN(i, j) << endl;

   return 0;
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

The minimum is 30

Compilation conditionnelle

Il existe plusieurs directives qui peuvent être utilisées pour compiler des portions sélectives du code source de votre programme. Ce processus est appelé compilation conditionnelle.

La construction du préprocesseur conditionnel ressemble beaucoup à la structure de sélection «si». Considérez le code de préprocesseur suivant -

#ifndef NULL
   #define NULL 0
#endif

Vous pouvez compiler un programme à des fins de débogage. Vous pouvez également activer ou désactiver le débogage à l'aide d'une seule macro comme suit -

#ifdef DEBUG
   cerr <<"Variable x = " << x << endl;
#endif

Cela provoque le cerrinstruction à compiler dans le programme si la constante symbolique DEBUG a été définie avant la directive #ifdef DEBUG. Vous pouvez utiliser l'instruction #if 0 pour commenter une partie du programme comme suit -

#if 0
   code prevented from compiling
#endif

Essayons l'exemple suivant -

#include <iostream>
using namespace std;
#define DEBUG

#define MIN(a,b) (((a)<(b)) ? a : b)

int main () {
   int i, j;
   
   i = 100;
   j = 30;

#ifdef DEBUG
   cerr <<"Trace: Inside main function" << endl;
#endif

#if 0
   /* This is commented part */
   cout << MKSTR(HELLO C++) << endl;
#endif

   cout <<"The minimum is " << MIN(i, j) << endl;

#ifdef DEBUG
   cerr <<"Trace: Coming out of main function" << endl;
#endif

   return 0;
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

The minimum is 30
Trace: Inside main function
Trace: Coming out of main function

Les opérateurs # et ##

Les opérateurs de préprocesseur # et ## sont disponibles en C ++ et ANSI / ISO C. L'opérateur # entraîne la conversion d'un jeton de texte de remplacement en une chaîne entourée de guillemets.

Considérez la définition de macro suivante -

#include <iostream>
using namespace std;

#define MKSTR( x ) #x

int main () {

   cout << MKSTR(HELLO C++) << endl;

   return 0;
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

HELLO C++

Voyons comment cela a fonctionné. Il est simple de comprendre que le préprocesseur C ++ tourne la ligne -

cout << MKSTR(HELLO C++) << endl;

La ligne ci-dessus sera transformée en ligne suivante -

cout << "HELLO C++" << endl;

L'opérateur ## est utilisé pour concaténer deux jetons. Voici un exemple -

#define CONCAT( x, y )  x ## y

Lorsque CONCAT apparaît dans le programme, ses arguments sont concaténés et utilisés pour remplacer la macro. Par exemple, CONCAT (HELLO, C ++) est remplacé par "HELLO C ++" dans le programme comme suit.

#include <iostream>
using namespace std;

#define concat(a, b) a ## b
int main() {
   int xy = 100;
   
   cout << concat(x, y);
   return 0;
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

100

Voyons comment cela a fonctionné. Il est simple de comprendre que le préprocesseur C ++ transforme -

cout << concat(x, y);

La ligne ci-dessus sera transformée en ligne suivante -

cout << xy;

Macros C ++ prédéfinies

C ++ fournit un certain nombre de macros prédéfinies mentionnées ci-dessous -

Sr.Non Macro et description
1

__LINE__

Celui-ci contient le numéro de ligne actuel du programme lors de sa compilation.

2

__FILE__

Il contient le nom de fichier actuel du programme lors de sa compilation.

3

__DATE__

Celui-ci contient une chaîne de la forme mois / jour / année qui correspond à la date de la traduction du fichier source en code objet.

4

__TIME__

Celui-ci contient une chaîne de la forme heure: minute: seconde qui correspond à l'heure à laquelle le programme a été compilé.

Voyons un exemple pour toutes les macros ci-dessus -

#include <iostream>
using namespace std;

int main () {
   cout << "Value of __LINE__ : " << __LINE__ << endl;
   cout << "Value of __FILE__ : " << __FILE__ << endl;
   cout << "Value of __DATE__ : " << __DATE__ << endl;
   cout << "Value of __TIME__ : " << __TIME__ << endl;

   return 0;
}

Si nous compilons et exécutons le code ci-dessus, cela produirait le résultat suivant -

Value of __LINE__ : 6
Value of __FILE__ : test.cpp
Value of __DATE__ : Feb 28 2011
Value of __TIME__ : 18:52:48

Les signaux sont les interruptions délivrées à un processus par le système d'exploitation qui peuvent mettre fin prématurément à un programme. Vous pouvez générer des interruptions en appuyant sur Ctrl + C sur un système UNIX, LINUX, Mac OS X ou Windows.

Il existe des signaux qui ne peuvent pas être captés par le programme, mais il existe une liste suivante de signaux que vous pouvez capturer dans votre programme et prendre les mesures appropriées en fonction du signal. Ces signaux sont définis dans le fichier d'en-tête C ++ <csignal>.

Sr.Non Signal et description
1

SIGABRT

Arrêt anormal du programme, tel qu'un appel à abort.

2

SIGFPE

Une opération arithmétique erronée, telle qu'une division par zéro ou une opération entraînant un débordement.

3

SIGILL

Détection d'une instruction illégale.

4

SIGINT

Réception d'un signal d'attention interactif.

5

SIGSEGV

Un accès non valide au stockage.

6

SIGTERM

Une demande de résiliation envoyée au programme.

La fonction signal ()

La bibliothèque de gestion de signaux C ++ fournit la fonction signalpour piéger les événements inattendus. Voici la syntaxe de la fonction signal () -

void (*signal (int sig, void (*func)(int)))(int);

Pour rester simple, cette fonction reçoit deux arguments: le premier argument sous la forme d'un entier qui représente le numéro du signal et le second argument comme un pointeur vers la fonction de gestion du signal.

Écrivons un simple programme C ++ où nous attraperons le signal SIGINT en utilisant la fonction signal (). Quel que soit le signal que vous souhaitez capturer dans votre programme, vous devez enregistrer ce signal en utilisantsignalfonction et associez-le à un gestionnaire de signaux. Examinez l'exemple suivant -

#include <iostream>
#include <csignal>

using namespace std;

void signalHandler( int signum ) {
   cout << "Interrupt signal (" << signum << ") received.\n";

   // cleanup and close up stuff here  
   // terminate program  

   exit(signum);  
}

int main () {
   // register signal SIGINT and signal handler  
   signal(SIGINT, signalHandler);  

   while(1) {
      cout << "Going to sleep...." << endl;
      sleep(1);
   }

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Going to sleep....
Going to sleep....
Going to sleep....

Maintenant, appuyez sur Ctrl + c pour interrompre le programme et vous verrez que votre programme captera le signal et sortira en imprimant quelque chose comme suit -

Going to sleep....
Going to sleep....
Going to sleep....
Interrupt signal (2) received.

La fonction rise ()

Vous pouvez générer des signaux par fonction raise(), qui prend un nombre de signal entier comme argument et a la syntaxe suivante.

int raise (signal sig);

Ici, sigest le numéro de signal pour envoyer l'un des signaux: SIGINT, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGTERM, SIGHUP. Voici l'exemple où nous élevons un signal en interne en utilisant la fonction rise () comme suit -

#include <iostream>
#include <csignal>

using namespace std;

void signalHandler( int signum ) {
   cout << "Interrupt signal (" << signum << ") received.\n";

   // cleanup and close up stuff here  
   // terminate program  

   exit(signum);  
}

int main () {
   int i = 0;
   // register signal SIGINT and signal handler  
   signal(SIGINT, signalHandler);  

   while(++i) {
      cout << "Going to sleep...." << endl;
      if( i == 3 ) {
         raise( SIGINT);
      }
      sleep(1);
   }

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant et sortira automatiquement -

Going to sleep....
Going to sleep....
Going to sleep....
Interrupt signal (2) received.

Le multithreading est une forme spécialisée de multitâche et un multitâche est la fonctionnalité qui permet à votre ordinateur d'exécuter simultanément deux programmes ou plus. En général, il existe deux types de multitâche: basé sur les processus et basé sur les threads.

Le multitâche basé sur les processus gère l'exécution simultanée des programmes. Le multitâche basé sur les threads traite de l'exécution simultanée d'éléments d'un même programme.

Un programme multithread contient deux ou plusieurs parties qui peuvent s'exécuter simultanément. Chaque partie d'un tel programme est appelée un thread, et chaque thread définit un chemin d'exécution distinct.

C ++ ne contient aucune prise en charge intégrée pour les applications multithread. Au lieu de cela, il repose entièrement sur le système d'exploitation pour fournir cette fonctionnalité.

Ce tutoriel suppose que vous travaillez sur Linux OS et que nous allons écrire un programme C ++ multi-thread en utilisant POSIX. POSIX Threads, ou Pthreads, fournit des API qui sont disponibles sur de nombreux systèmes POSIX de type Unix tels que FreeBSD, NetBSD, GNU / Linux, Mac OS X et Solaris.

Créer des threads

La routine suivante est utilisée pour créer un thread POSIX -

#include <pthread.h>
pthread_create (thread, attr, start_routine, arg)

Ici, pthread_createcrée un nouveau thread et le rend exécutable. Cette routine peut être appelée un certain nombre de fois à partir de n'importe où dans votre code. Voici la description des paramètres -

Sr.Non Paramètre et description
1

thread

Un identifiant unique et opaque pour le nouveau thread renvoyé par le sous-programme.

2

attr

Un objet attribut opaque qui peut être utilisé pour définir des attributs de thread. Vous pouvez spécifier un objet d'attributs de thread ou NULL pour les valeurs par défaut.

3

start_routine

La routine C ++ que le thread exécutera une fois qu'il est créé.

4

arg

Un seul argument qui peut être passé à start_routine. Il doit être passé par référence comme un cast de pointeur de type void. NULL peut être utilisé si aucun argument ne doit être passé.

Le nombre maximum de threads pouvant être créés par un processus dépend de l'implémentation. Une fois créés, les threads sont pairs et peuvent créer d'autres threads. Il n'y a pas de hiérarchie ou de dépendance implicite entre les threads.

Terminer les threads

Il y a la routine suivante que nous utilisons pour terminer un thread POSIX -

#include <pthread.h>
pthread_exit (status)

Ici pthread_exitest utilisé pour quitter explicitement un thread. En règle générale, la routine pthread_exit () est appelée après qu'un thread a terminé son travail et n'est plus nécessaire d'exister.

Si main () se termine avant les threads qu'il a créés et quitte avec pthread_exit (), les autres threads continueront à s'exécuter. Sinon, ils seront automatiquement interrompus lorsque main () se terminera.

Example

Cet exemple de code simple crée 5 threads avec la routine pthread_create (). Chaque fil imprime un "Hello World!" message, puis se termine par un appel à pthread_exit ().

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

void *PrintHello(void *threadid) {
   long tid;
   tid = (long)threadid;
   cout << "Hello World! Thread ID, " << tid << endl;
   pthread_exit(NULL);
}

int main () {
   pthread_t threads[NUM_THREADS];
   int rc;
   int i;
   
   for( i = 0; i < NUM_THREADS; i++ ) {
      cout << "main() : creating thread, " << i << endl;
      rc = pthread_create(&threads[i], NULL, PrintHello, (void *)i);
      
      if (rc) {
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

Compilez le programme suivant en utilisant la bibliothèque -lpthread comme suit -

$gcc test.cpp -lpthread

Maintenant, exécutez votre programme qui donne la sortie suivante -

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Hello World! Thread ID, 0
Hello World! Thread ID, 1
Hello World! Thread ID, 2
Hello World! Thread ID, 3
Hello World! Thread ID, 4

Passer des arguments aux threads

Cet exemple montre comment passer plusieurs arguments via une structure. Vous pouvez transmettre n'importe quel type de données dans un rappel de thread car il pointe vers void, comme expliqué dans l'exemple suivant -

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

struct thread_data {
   int  thread_id;
   char *message;
};

void *PrintHello(void *threadarg) {
   struct thread_data *my_data;
   my_data = (struct thread_data *) threadarg;

   cout << "Thread ID : " << my_data->thread_id ;
   cout << " Message : " << my_data->message << endl;

   pthread_exit(NULL);
}

int main () {
   pthread_t threads[NUM_THREADS];
   struct thread_data td[NUM_THREADS];
   int rc;
   int i;

   for( i = 0; i < NUM_THREADS; i++ ) {
      cout <<"main() : creating thread, " << i << endl;
      td[i].thread_id = i;
      td[i].message = "This is message";
      rc = pthread_create(&threads[i], NULL, PrintHello, (void *)&td[i]);
      
      if (rc) {
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Thread ID : 3 Message : This is message
Thread ID : 2 Message : This is message
Thread ID : 0 Message : This is message
Thread ID : 1 Message : This is message
Thread ID : 4 Message : This is message

Rejoindre et détacher des threads

Il existe deux routines suivantes que nous pouvons utiliser pour joindre ou détacher des threads -

pthread_join (threadid, status) 
pthread_detach (threadid)

La sous-routine pthread_join () bloque le thread appelant jusqu'à ce que le thread spécifié 'threadid' se termine. Lorsqu'un thread est créé, l'un de ses attributs définit s'il peut être joint ou détaché. Seuls les threads créés comme joignables peuvent être joints. Si un thread est créé comme détaché, il ne peut jamais être joint.

Cet exemple montre comment attendre la fin des threads à l'aide de la routine de jointure Pthread.

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>

using namespace std;

#define NUM_THREADS 5

void *wait(void *t) {
   int i;
   long tid;

   tid = (long)t;

   sleep(1);
   cout << "Sleeping in thread " << endl;
   cout << "Thread with id : " << tid << "  ...exiting " << endl;
   pthread_exit(NULL);
}

int main () {
   int rc;
   int i;
   pthread_t threads[NUM_THREADS];
   pthread_attr_t attr;
   void *status;

   // Initialize and set thread joinable
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

   for( i = 0; i < NUM_THREADS; i++ ) {
      cout << "main() : creating thread, " << i << endl;
      rc = pthread_create(&threads[i], &attr, wait, (void *)i );

      
      if (rc) {
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }

   // free attribute and wait for the other threads
   pthread_attr_destroy(&attr);
   for( i = 0; i < NUM_THREADS; i++ ) {
      rc = pthread_join(threads[i], &status);
      if (rc) {
         cout << "Error:unable to join," << rc << endl;
         exit(-1);
      }
      
      cout << "Main: completed thread id :" << i ;
      cout << "  exiting with status :" << status << endl;
   }

   cout << "Main: program exiting." << endl;
   pthread_exit(NULL);
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Sleeping in thread
Thread with id : 0 .... exiting
Sleeping in thread
Thread with id : 1 .... exiting
Sleeping in thread
Thread with id : 2 .... exiting
Sleeping in thread
Thread with id : 3 .... exiting
Sleeping in thread
Thread with id : 4 .... exiting
Main: completed thread id :0  exiting with status :0
Main: completed thread id :1  exiting with status :0
Main: completed thread id :2  exiting with status :0
Main: completed thread id :3  exiting with status :0
Main: completed thread id :4  exiting with status :0
Main: program exiting.

Qu'est-ce que CGI?

  • L'interface de passerelle commune, ou CGI, est un ensemble de normes qui définissent la manière dont les informations sont échangées entre le serveur Web et un script personnalisé.

  • Les spécifications CGI sont actuellement maintenues par le NCSA et NCSA définit CGI comme suit -

  • L'interface de passerelle commune, ou CGI, est une norme permettant aux programmes de passerelle externes de s'interfacer avec des serveurs d'informations tels que des serveurs HTTP.

  • La version actuelle est CGI / 1.1 et CGI / 1.2 est en cours de développement.

Navigation sur le Web

Pour comprendre le concept de CGI, voyons ce qui se passe lorsque nous cliquons sur un lien hypertexte pour parcourir une page Web ou une URL particulière.

  • Votre navigateur contacte le serveur Web HTTP et demande l'URL, c.-à-d. nom de fichier.

  • Web Server analysera l'URL et recherchera le nom de fichier. S'il trouve le fichier demandé, le serveur Web renvoie ce fichier au navigateur, sinon envoie un message d'erreur indiquant que vous avez demandé un mauvais fichier.

  • Le navigateur Web prend la réponse du serveur Web et affiche le fichier reçu ou le message d'erreur en fonction de la réponse reçue.

Cependant, il est possible de configurer le serveur HTTP de telle manière que chaque fois qu'un fichier dans un certain répertoire est demandé, ce fichier n'est pas renvoyé; au lieu de cela, il est exécuté en tant que programme et la sortie produite à partir du programme est renvoyée à votre navigateur pour être affichée.

L'interface de passerelle commune (CGI) est un protocole standard permettant aux applications (appelées programmes CGI ou scripts CGI) d'interagir avec les serveurs Web et les clients. Ces programmes CGI peuvent être écrits en Python, PERL, Shell, C ou C ++ etc.

Diagramme d'architecture CGI

Le programme simple suivant montre une architecture simple de CGI -

Configuration du serveur Web

Avant de poursuivre la programmation CGI, assurez-vous que votre serveur Web prend en charge CGI et qu'il est configuré pour gérer les programmes CGI. Tous les programmes CGI à exécuter par le serveur HTTP sont conservés dans un répertoire préconfiguré. Ce répertoire est appelé répertoire CGI et par convention, il est nommé comme / var / www / cgi-bin. Par convention, les fichiers CGI auront l'extension comme.cgi, bien qu'ils soient exécutables C ++.

Par défaut, Apache Web Server est configuré pour exécuter les programmes CGI dans / var / www / cgi-bin. Si vous souhaitez spécifier un autre répertoire pour exécuter vos scripts CGI, vous pouvez modifier la section suivante dans le fichier httpd.conf -

<Directory "/var/www/cgi-bin">
   AllowOverride None
   Options ExecCGI
   Order allow,deny
   Allow from all
</Directory>
 
<Directory "/var/www/cgi-bin">
   Options All
</Directory>

Ici, je suppose que Web Server est opérationnel avec succès et que vous pouvez exécuter n'importe quel autre programme CGI comme Perl ou Shell, etc.

Premier programme CGI

Considérez le contenu du programme C ++ suivant -

#include <iostream>
using namespace std;

int main () {
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Hello World - First CGI Program</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<h2>Hello World! This is my first CGI program</h2>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Compilez le code ci-dessus et nommez l'exécutable cplusplus.cgi. Ce fichier est conservé dans le répertoire / var / www / cgi-bin et a le contenu suivant. Avant d'exécuter votre programme CGI, assurez-vous que vous avez changé le mode de fichier en utilisantchmod 755 cplusplus.cgi Commande UNIX pour rendre le fichier exécutable.

Mon premier programme CGI

Le programme C ++ ci-dessus est un programme simple qui écrit sa sortie sur un fichier STDOUT, c'est-à-dire un écran. Il existe une fonctionnalité importante et supplémentaire disponible qui est l'impression de première ligneContent-type:text/html\r\n\r\n. Cette ligne est renvoyée au navigateur et spécifie le type de contenu à afficher sur l'écran du navigateur. Vous devez maintenant avoir compris le concept de base de CGI et vous pouvez écrire de nombreux programmes CGI compliqués en utilisant Python. Un programme C ++ CGI peut interagir avec tout autre système externe, tel que le SGBDR, pour échanger des informations.

En-tête HTTP

La ligne Content-type:text/html\r\n\r\nfait partie de l'en-tête HTTP, qui est envoyé au navigateur pour comprendre le contenu. Tout l'en-tête HTTP sera sous la forme suivante -

HTTP Field Name: Field Content
 
For Example
Content-type: text/html\r\n\r\n

Il existe quelques autres en-têtes HTTP importants que vous utiliserez fréquemment dans votre programmation CGI.

Sr.Non En-tête et description
1

Content-type:

Une chaîne MIME définissant le format du fichier renvoyé. L'exemple est Content-type: text / html.

2

Expires: Date

La date à laquelle les informations deviennent invalides. Cela doit être utilisé par le navigateur pour décider quand une page doit être actualisée. Une chaîne de date valide doit être au format 01 janvier 1998 12:00:00 GMT.

3

Location: URL

L'URL qui doit être renvoyée à la place de l'URL demandée. Vous pouvez utiliser ce fichier pour rediriger une demande vers n'importe quel fichier.

4

Last-modified: Date

La date de la dernière modification de la ressource.

5

Content-length: N

La longueur, en octets, des données renvoyées. Le navigateur utilise cette valeur pour rapporter le temps de téléchargement estimé d'un fichier.

6

Set-Cookie: String

Définissez le cookie transmis par la chaîne .

Variables d'environnement CGI

Tout le programme CGI aura accès aux variables d'environnement suivantes. Ces variables jouent un rôle important lors de l'écriture de tout programme CGI.

Sr.Non Nom et description de la variable
1

CONTENT_TYPE

Le type de données du contenu, utilisé lorsque le client envoie du contenu joint au serveur. Par exemple, téléchargement de fichiers, etc.

2

CONTENT_LENGTH

Longueur des informations de requête disponibles uniquement pour les requêtes POST.

3

HTTP_COOKIE

Renvoie les cookies définis sous la forme d'une paire clé / valeur.

4

HTTP_USER_AGENT

Le champ d'en-tête de demande User-Agent contient des informations sur l'agent utilisateur à l'origine de la demande. C'est un nom du navigateur Web.

5

PATH_INFO

Le chemin du script CGI.

6

QUERY_STRING

Informations encodées en URL envoyées avec la demande de méthode GET.

sept

REMOTE_ADDR

L'adresse IP de l'hôte distant effectuant la demande. Cela peut être utile pour la journalisation ou à des fins d'authentification.

8

REMOTE_HOST

Le nom complet de l'hôte effectuant la demande. Si ces informations ne sont pas disponibles, REMOTE_ADDR peut être utilisé pour obtenir l'adresse IR.

9

REQUEST_METHOD

La méthode utilisée pour faire la demande. Les méthodes les plus courantes sont GET et POST.

dix

SCRIPT_FILENAME

Le chemin complet du script CGI.

11

SCRIPT_NAME

Le nom du script CGI.

12

SERVER_NAME

Le nom d'hôte ou l'adresse IP du serveur.

13

SERVER_SOFTWARE

Le nom et la version du logiciel exécuté par le serveur.

Voici un petit programme CGI pour lister toutes les variables CGI.

#include <iostream>
#include <stdlib.h>
using namespace std;

const string ENV[ 24 ] = {
   "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE",   
   "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING",             
   "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION",         
   "HTTP_HOST", "HTTP_USER_AGENT", "PATH",            
   "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT",      
   "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME",
   "SCRIPT_NAME", "SERVER_ADDR", "SERVER_ADMIN",      
   "SERVER_NAME","SERVER_PORT","SERVER_PROTOCOL",     
   "SERVER_SIGNATURE","SERVER_SOFTWARE" };   

int main () {
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>CGI Environment Variables</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<table border = \"0\" cellspacing = \"2\">";

   for ( int i = 0; i < 24; i++ ) {
      cout << "<tr><td>" << ENV[ i ] << "</td><td>";
      
      // attempt to retrieve value of environment variable
      char *value = getenv( ENV[ i ].c_str() );  
      if ( value != 0 ) {
         cout << value;                                 
      } else {
         cout << "Environment variable does not exist.";
      }
      cout << "</td></tr>\n";
   }
   
   cout << "</table><\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Bibliothèque C ++ CGI

Pour de vrais exemples, vous auriez besoin de faire de nombreuses opérations par votre programme CGI. Il existe une bibliothèque CGI écrite pour le programme C ++ que vous pouvez télécharger à partir de ftp://ftp.gnu.org/gnu/cgicc/ et suivez les étapes pour installer la bibliothèque -

$tar xzf cgicc-X.X.X.tar.gz 
$cd cgicc-X.X.X/ $./configure --prefix=/usr 
$make $make install

Vous pouvez consulter la documentation connexe disponible sur 'C ++ CGI Lib Documentation .

Méthodes GET et POST

Vous devez avoir rencontré de nombreuses situations où vous devez transmettre certaines informations de votre navigateur à un serveur Web et finalement à votre programme CGI. Le navigateur utilise le plus souvent deux méthodes pour transmettre ces informations au serveur Web. Ces méthodes sont la méthode GET et la méthode POST.

Transmission d'informations à l'aide de la méthode GET

La méthode GET envoie les informations utilisateur codées ajoutées à la demande de page. La page et les informations encodées sont séparées par le? caractère comme suit -

http://www.test.com/cgi-bin/cpp.cgi?key1=value1&key2=value2

La méthode GET est la méthode par défaut pour transmettre des informations du navigateur au serveur Web et elle produit une longue chaîne qui apparaît dans la zone Emplacement: de votre navigateur. N'utilisez jamais la méthode GET si vous avez un mot de passe ou d'autres informations sensibles à transmettre au serveur. La méthode GET a une limitation de taille et vous pouvez passer jusqu'à 1024 caractères dans une chaîne de requête.

Lorsque vous utilisez la méthode GET, les informations sont transmises à l'aide de l'en-tête http QUERY_STRING et seront accessibles dans votre programme CGI via la variable d'environnement QUERY_STRING.

Vous pouvez transmettre des informations en concaténant simplement des paires clé et valeur avec n'importe quelle URL ou vous pouvez utiliser des balises HTML <FORM> pour transmettre des informations à l'aide de la méthode GET.

Exemple d'URL simple: méthode Get

Voici une URL simple qui transmettra deux valeurs au programme hello_get.py en utilisant la méthode GET.

/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI

Voici un programme pour générer cpp_get.cgiProgramme CGI pour gérer les entrées fournies par le navigateur Web. Nous allons utiliser la bibliothèque C ++ CGI qui facilite l'accès aux informations transmises -

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h>  

using namespace std;
using namespace cgicc;

int main () {
   Cgicc formData;
   
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Using GET and POST Methods</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("first_name");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "First name: " << **fi << endl;  
   } else {
      cout << "No text entered for first name" << endl;  
   }
   
   cout << "<br/>\n";
   fi = formData.getElement("last_name");  
   if( !fi->isEmpty() &&fi != (*formData).end()) {  
      cout << "Last name: " << **fi << endl;  
   } else {
      cout << "No text entered for last name" << endl;  
   }
   
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Maintenant, compilez le programme ci-dessus comme suit -

$g++ -o cpp_get.cgi cpp_get.cpp -lcgicc

Générez cpp_get.cgi et placez-le dans votre répertoire CGI et essayez d'accéder en utilisant le lien suivant -

/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI

Cela générerait le résultat suivant -

First name: ZARA 
Last name: ALI

Exemple de formulaire simple: méthode GET

Voici un exemple simple qui transmet deux valeurs à l'aide du formulaire HTML et du bouton d'envoi. Nous allons utiliser le même script CGI cpp_get.cgi pour gérer cette entrée.

<form action = "/cgi-bin/cpp_get.cgi" method = "get">
   First Name: <input type = "text" name = "first_name">  <br />
 
   Last Name: <input type = "text" name = "last_name" />
   <input type = "submit" value = "Submit" />
</form>

Voici la sortie réelle du formulaire ci-dessus. Vous entrez le prénom et le nom, puis cliquez sur le bouton Soumettre pour voir le résultat.

Transmission d'informations à l'aide de la méthode POST

Une méthode généralement plus fiable pour transmettre des informations à un programme CGI est la méthode POST. Cela regroupe les informations exactement de la même manière que les méthodes GET, mais au lieu de les envoyer sous forme de chaîne de texte après un? dans l'URL, il l'envoie sous forme de message séparé. Ce message entre dans le script CGI sous la forme de l'entrée standard.

Le même programme cpp_get.cgi gérera également la méthode POST. Prenons le même exemple que ci-dessus, qui passe deux valeurs en utilisant HTML FORM et le bouton d'envoi mais cette fois avec la méthode POST comme suit -

<form action = "/cgi-bin/cpp_get.cgi" method = "post">
   First Name: <input type = "text" name = "first_name"><br />
   Last Name: <input type = "text" name = "last_name" />
 
   <input type = "submit" value = "Submit" />
</form>

Voici la sortie réelle du formulaire ci-dessus. Vous entrez le prénom et le nom, puis cliquez sur le bouton Soumettre pour voir le résultat.

Transmission des données de case à cocher au programme CGI

Les cases à cocher sont utilisées lorsque plusieurs options doivent être sélectionnées.

Voici un exemple de code HTML pour un formulaire avec deux cases à cocher -

<form action = "/cgi-bin/cpp_checkbox.cgi" method = "POST" target = "_blank">
   <input type = "checkbox" name = "maths" value = "on" /> Maths
   <input type = "checkbox" name = "physics" value = "on" /> Physics
   <input type = "submit" value = "Select Subject" />
</form>

Le résultat de ce code est la forme suivante -

Vous trouverez ci-dessous le programme C ++, qui générera le script cpp_checkbox.cgi pour gérer les entrées fournies par le navigateur Web via le bouton de la case à cocher.

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h> 

using namespace std;
using namespace cgicc;

int main () {
   Cgicc formData;
   bool maths_flag, physics_flag;

   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Checkbox Data to CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   maths_flag = formData.queryCheckbox("maths");
   if( maths_flag ) {  
      cout << "Maths Flag: ON " << endl;  
   } else {
      cout << "Maths Flag: OFF " << endl;  
   }
   cout << "<br/>\n";

   physics_flag = formData.queryCheckbox("physics");
   if( physics_flag ) {  
      cout << "Physics Flag: ON " << endl;  
   } else {
      cout << "Physics Flag: OFF " << endl;  
   }
   
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Transmission des données de bouton radio au programme CGI

Les boutons radio sont utilisés lorsqu'une seule option doit être sélectionnée.

Voici un exemple de code HTML pour un formulaire avec deux boutons radio -

<form action = "/cgi-bin/cpp_radiobutton.cgi" method = "post" target = "_blank">
   <input type = "radio" name = "subject" value = "maths" checked = "checked"/> Maths 
   <input type = "radio" name = "subject" value = "physics" /> Physics
   <input type = "submit" value = "Select Subject" />
</form>

Le résultat de ce code est la forme suivante -

Ci-dessous se trouve le programme C ++, qui générera le script cpp_radiobutton.cgi pour gérer les entrées fournies par le navigateur Web via les boutons radio.

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h> 

using namespace std;
using namespace cgicc;

int main () {
   Cgicc formData;
  
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Radio Button Data to CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("subject");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "Radio box selected: " << **fi << endl;  
   }
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Transmission de données de zone de texte au programme CGI

L'élément TEXTAREA est utilisé lorsqu'un texte multiligne doit être transmis au programme CGI.

Voici un exemple de code HTML pour un formulaire avec une zone TEXTAREA -

<form action = "/cgi-bin/cpp_textarea.cgi" method = "post" target = "_blank">
   <textarea name = "textcontent" cols = "40" rows = "4">
      Type your text here...
   </textarea>
   <input type = "submit" value = "Submit" />
</form>

Le résultat de ce code est la forme suivante -

Vous trouverez ci-dessous le programme C ++, qui générera un script cpp_textarea.cgi pour gérer les entrées fournies par le navigateur Web via la zone de texte.

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h> 

using namespace std;
using namespace cgicc;

int main () {
   Cgicc formData;
  
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Text Area Data to CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("textcontent");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "Text Content: " << **fi << endl;  
   } else {
      cout << "No text entered" << endl;  
   }
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Transmission de données de boîte déroulante au programme CGI

La boîte déroulante est utilisée lorsque de nombreuses options sont disponibles mais qu'une ou deux seulement seront sélectionnées.

Voici un exemple de code HTML pour un formulaire avec une liste déroulante -

<form action = "/cgi-bin/cpp_dropdown.cgi" method = "post" target = "_blank">
   <select name = "dropdown">
      <option value = "Maths" selected>Maths</option>
      <option value = "Physics">Physics</option>
   </select>
   
   <input type = "submit" value = "Submit"/>
</form>

Le résultat de ce code est la forme suivante -

Vous trouverez ci-dessous le programme C ++, qui générera un script cpp_dropdown.cgi pour gérer les entrées fournies par le navigateur Web via la liste déroulante.

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h> 

using namespace std;
using namespace cgicc;

int main () {
   Cgicc formData;
  
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Drop Down Box Data to CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("dropdown");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "Value Selected: " << **fi << endl;  
   }
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Utilisation de cookies dans CGI

Le protocole HTTP est un protocole sans état. Mais pour un site Web commercial, il est nécessaire de conserver les informations de session entre différentes pages. Par exemple, l'enregistrement d'un utilisateur se termine après avoir terminé de nombreuses pages. Mais comment conserver les informations de session de l'utilisateur sur toutes les pages Web.

Dans de nombreuses situations, l'utilisation de cookies est la méthode la plus efficace pour mémoriser et suivre les préférences, les achats, les commissions et d'autres informations nécessaires pour une meilleure expérience des visiteurs ou des statistiques du site.

Comment ça fonctionne

Votre serveur envoie certaines données au navigateur du visiteur sous la forme d'un cookie. Le navigateur peut accepter le cookie. Si tel est le cas, il est stocké sous forme d'enregistrement en texte brut sur le disque dur du visiteur. Désormais, lorsque le visiteur arrive sur une autre page de votre site, le cookie est disponible pour la récupération. Une fois récupéré, votre serveur sait / se souvient de ce qui a été stocké.

Les cookies sont un enregistrement de données en texte brut de 5 champs de longueur variable -

  • Expires- Cela indique la date d'expiration du cookie. Si ce champ est vide, le cookie expirera lorsque le visiteur quittera le navigateur.

  • Domain - Cela montre le nom de domaine de votre site.

  • Path- Cela montre le chemin vers le répertoire ou la page Web qui a défini le cookie. Cela peut être vide si vous souhaitez récupérer le cookie à partir de n'importe quel répertoire ou page.

  • Secure- Si ce champ contient le mot «sécurisé», alors le cookie ne peut être récupéré qu'avec un serveur sécurisé. Si ce champ est vide, une telle restriction n'existe pas.

  • Name = Value - Les cookies sont définis et récupérés sous la forme de paires clé et valeur.

Configurer les cookies

Il est très facile d'envoyer des cookies au navigateur. Ces cookies seront envoyés avec l'en-tête HTTP avant le type de contenu classé. En supposant que vous souhaitiez définir l'ID utilisateur et le mot de passe en tant que cookies. Ainsi, la configuration des cookies sera effectuée comme suit

#include <iostream>
using namespace std;

int main () {
   cout << "Set-Cookie:UserID = XYZ;\r\n";
   cout << "Set-Cookie:Password = XYZ123;\r\n";
   cout << "Set-Cookie:Domain = www.tutorialspoint.com;\r\n";
   cout << "Set-Cookie:Path = /perl;\n";
   cout << "Content-type:text/html\r\n\r\n";

   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Cookies in CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   cout << "Setting cookies" << endl;  
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

A partir de cet exemple, vous devez avoir compris comment configurer les cookies. Nous utilisonsSet-Cookie En-tête HTTP pour définir les cookies.

Ici, il est facultatif de définir des attributs de cookies tels que Expire, Domain et Path. Il est à noter que les cookies sont définis avant l'envoi de la ligne magique"Content-type:text/html\r\n\r\n.

Compilez le programme ci-dessus pour produire setcookies.cgi et essayez de définir des cookies en utilisant le lien suivant. Il installera quatre cookies sur votre ordinateur -

/cgi-bin/setcookies.cgi

Récupération des cookies

Il est facile de récupérer tous les cookies définis. Les cookies sont stockés dans la variable d'environnement CGI HTTP_COOKIE et ils auront la forme suivante.

key1 = value1; key2 = value2; key3 = value3....

Voici un exemple de récupération des cookies.

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main () {
   Cgicc cgi;
   const_cookie_iterator cci;

   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Cookies in CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<table border = \"0\" cellspacing = \"2\">";
   
   // get environment variables
   const CgiEnvironment& env = cgi.getEnvironment();

   for( cci = env.getCookieList().begin();
   cci != env.getCookieList().end(); 
   ++cci ) {
      cout << "<tr><td>" << cci->getName() << "</td><td>";
      cout << cci->getValue();                                 
      cout << "</td></tr>\n";
   }
   
   cout << "</table><\n";
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Maintenant, compilez le programme ci-dessus pour produire getcookies.cgi, et essayez d'obtenir une liste de tous les cookies disponibles sur votre ordinateur -

/cgi-bin/getcookies.cgi

Cela produira une liste des quatre cookies définis dans la section précédente et de tous les autres cookies installés sur votre ordinateur -

UserID XYZ 
Password XYZ123 
Domain www.tutorialspoint.com 
Path /perl

Exemple de téléchargement de fichier

Pour télécharger un fichier, le formulaire HTML doit avoir l'attribut enctype défini sur multipart/form-data. La balise d'entrée avec le type de fichier créera un bouton "Parcourir".

<html>
   <body>
      <form enctype = "multipart/form-data" action = "/cgi-bin/cpp_uploadfile.cgi"
         method = "post">
         <p>File: <input type = "file" name = "userfile" /></p>
         <p><input type = "submit" value = "Upload" /></p>
      </form>
   </body>
</html>

Le résultat de ce code est la forme suivante -

Note- L'exemple ci-dessus a été désactivé intentionnellement pour empêcher les gens de télécharger des fichiers sur notre serveur. Mais vous pouvez essayer le code ci-dessus avec votre serveur.

Voici le script cpp_uploadfile.cpp pour gérer le téléchargement de fichiers -

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main () {
   Cgicc cgi;

   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>File Upload in CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   // get list of files to be uploaded
   const_file_iterator file = cgi.getFile("userfile");
   if(file != cgi.getFiles().end()) {
      // send data type at cout.
      cout << HTTPContentHeader(file->getDataType());
      // write content at cout.
      file->writeToStream(cout);
   }
   cout << "<File uploaded successfully>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

L'exemple ci-dessus est pour écrire du contenu à cout stream mais vous pouvez ouvrir votre flux de fichiers et enregistrer le contenu du fichier téléchargé dans un fichier à l'emplacement souhaité.

J'espère que vous avez apprécié ce tutoriel. Si oui, veuillez nous envoyer vos commentaires.