C++Démarrer avec C ++

Download C++ for free

Remarques

Le programme 'Hello World' est un exemple courant qui peut être simplement utilisé pour vérifier la présence du compilateur et de la bibliothèque. Il utilise la bibliothèque standard C ++, avec std::cout de <iostream> , et ne dispose que d’un seul fichier à compiler, ce qui réduit les risques d’erreurs lors de la compilation.


Le processus de compilation d'un programme C ++ diffère intrinsèquement entre les compilateurs et les systèmes d'exploitation. La rubrique Compilation et construction contient les détails sur la façon de compiler du code C ++ sur différentes plates-formes pour différents compilateurs.

Versions

Version la norme Date de sortie
C ++ 98 ISO / IEC 14882: 1998 1998-09-01
C ++ 03 ISO / IEC 14882: 2003 2003-10-16
C ++ 11 ISO / IEC 14882: 2011 2011-09-01
C ++ 14 ISO / IEC 14882: 2014 2014-12-15
C ++ 17 À déterminer 2017-01-01
C ++ 20 À déterminer 2020-01-01

Bonjour le monde

Ce programme imprime Hello World! au flux de sortie standard:

#include <iostream>

int main()
{
    std::cout << "Hello World!" << std::endl;
}
 

Voyez-le vivre sur Coliru .

Une analyse

Examinons chaque partie de ce code en détail:

  • #include <iostream> est une directive de préprocesseur qui inclut le contenu du fichier d'en-tête C ++ standard iostream .

    iostream est un fichier d'en-tête de bibliothèque standard qui contient les définitions des flux d'entrée et de sortie standard. Ces définitions sont incluses dans l'espace de noms std , expliqué ci-dessous.

    Les flux d'entrée / sortie (E / S) standard permettent aux programmes d'obtenir des entrées et des sorties vers un système externe - généralement le terminal.

  • int main() { ... } définit une nouvelle fonction nommée main . Par convention, la fonction main est appelée lors de l'exécution du programme. Il ne doit y avoir qu'une seule fonction main dans un programme C ++, et il doit toujours renvoyer un numéro du type int .

    Ici, l' int est ce qu'on appelle le type de retour de la fonction. La valeur renvoyée par la fonction main est un code de sortie.

    Par convention, un code de sortie de programme de 0 ou EXIT_SUCCESS est interprété comme un succès par un système qui exécute le programme. Tout autre code de retour est associé à une erreur.

    Si aucune instruction de return n'est présente, la fonction main (et donc le programme lui-même) renvoie 0 par défaut. Dans cet exemple, nous n'avons pas besoin d'écrire explicitement return 0; .

    Toutes les autres fonctions, sauf celles qui renvoient le type void , doivent explicitement renvoyer une valeur en fonction de leur type de retour, sinon elles ne doivent pas être renvoyées du tout.

  • std::cout << "Hello World!" << std::endl; imprime "Hello World!" au flux de sortie standard:

    • std est un espace de noms , et :: est l' opérateur de résolution de portée qui permet de rechercher des objets par nom dans un espace de noms.

      Il y a beaucoup d'espaces de noms. Ici, nous utilisons :: pour montrer que nous voulons utiliser cout depuis l'espace de noms std . Pour plus d'informations, reportez-vous à Opérateur Résolution de portée - Documentation Microsoft .

    • std::cout est l'objet de flux de sortie standard , défini dans iostream , et il imprime sur la sortie standard ( stdout ).

    • << est, dans ce contexte , l' opérateur d'insertion de flux , ainsi appelé car il insère un objet dans l'objet flux .

      La bibliothèque standard définit l'opérateur << permettant d'insérer des données pour certains types de données dans les flux de sortie. stream << content insère du content dans le flux et renvoie le même flux, mais mis à jour. Cela permet de chaîner les insertions de flux: std::cout << "Foo" << " Bar"; imprime "FooBar" sur la console.

    • "Hello World!" est un littéral de chaîne de caractères ou un "littéral de texte". L'opérateur d'insertion de flux pour les littéraux de chaîne de caractères est défini dans le fichier iostream .

    • std::endl est un objet manipulateur de flux d'E / S spécial, également défini dans le fichier iostream . L'insertion d'un manipulateur dans un flux modifie l'état du flux.

      Le flux manipulateur std::endl fait deux choses: d'abord il insère le caractère de fin de ligne, puis il vide le tampon de flux pour forcer le texte à apparaître sur la console. Cela garantit que les données insérées dans le flux apparaissent réellement sur votre console. (Les données de flux sont généralement stockées dans un tampon puis "vidées" par lots, sauf si vous forcez un vidage immédiat.)

      Une autre méthode qui évite le flush est:

      std::cout << "Hello World!\n";
       

      \n est la séquence d'échappement de caractère pour le caractère de nouvelle ligne.

    • Le point-virgule ( ; ) informe le compilateur qu'une instruction est terminée. Toutes les instructions et définitions de classe C ++ nécessitent un point-virgule de fin / de fin.

commentaires

Un commentaire est un moyen de placer du texte arbitraire dans le code source sans que le compilateur C ++ l'interprète avec une signification fonctionnelle. Les commentaires permettent de mieux comprendre la conception ou la méthode d’un programme.

Il existe deux types de commentaires en C ++:

Commentaires sur une seule ligne

La double séquence de barre oblique avant // marquera tout le texte jusqu'à une nouvelle ligne en tant que commentaire:

int main()
{
   // This is a single-line comment.
   int a;  // this also is a single-line comment
   int i;  // this is another single-line comment
}
 

C-Style / Bloc Commentaires

La séquence /* est utilisée pour déclarer le début du bloc de commentaires et la séquence */ est utilisée pour déclarer la fin du commentaire. Tout le texte entre les séquences de début et de fin est interprété comme un commentaire, même si le texte est une syntaxe C ++ valide. Ceux-ci sont parfois appelés "style C" commentaires, car cette syntaxe de commentaire est héritée du langage prédécesseur de C ++, C:

int main()
{
   /*
    *  This is a block comment.
    */
   int a;
}
 

Dans tout commentaire de bloc, vous pouvez écrire tout ce que vous voulez. Lorsque le compilateur rencontre le symbole */ , il termine le commentaire de bloc:

int main()
{
   /* A block comment with the symbol /*
      Note that the compiler is not affected by the second /*
      however, once the end-block-comment symbol is reached,
      the comment ends.
   */
   int a;
}
 

L'exemple ci-dessus est un code C ++ (et C) valide. Cependant, le fait d’avoir des /* supplémentaires dans un commentaire de bloc peut entraîner un avertissement sur certains compilateurs.

Les commentaires de bloc peuvent également commencer et se terminer sur une seule ligne. Par exemple:

void SomeFunction(/* argument 1 */ int a, /* argument 2 */ int b);
 

Importance des commentaires

Comme avec tous les langages de programmation, les commentaires offrent plusieurs avantages:

  • Documentation explicite du code pour faciliter la lecture / maintenance
  • Explication du but et de la fonctionnalité du code
  • Détails sur l'historique ou le raisonnement derrière le code
  • Placement des droits d'auteur / licences, notes de projet, remerciements spéciaux, crédits contributeurs, etc. directement dans le code source.

Cependant, les commentaires ont aussi leurs inconvénients:

  • Ils doivent être maintenus pour refléter toute modification du code
  • Les commentaires excessifs ont tendance à rendre le code moins lisible

Le besoin de commentaires peut être réduit en écrivant un code clair et auto-documenté. Un exemple simple est l'utilisation de noms explicatifs pour les variables, les fonctions et les types. La prise en compte des tâches liées logiquement dans des fonctions distinctes va de pair avec cela.

Marqueurs de commentaires utilisés pour désactiver le code

Pendant le développement, les commentaires peuvent également être utilisés pour désactiver rapidement des parties de code sans les supprimer. Ceci est souvent utile à des fins de test ou de débogage, mais ce n'est pas un bon style pour autre chose que des modifications temporaires. C'est ce que l'on appelle souvent «commenter».

De même, conserver les anciennes versions d'un code dans un commentaire à des fins de référence est mal vu car il encombre les fichiers tout en offrant peu de valeur par rapport à l'exploration de l'historique du code via un système de gestion des versions.

Fonction

Une fonction est une unité de code qui représente une séquence d'instructions.

Les fonctions peuvent accepter des arguments ou des valeurs et renvoyer une seule valeur (ou non). Pour utiliser une fonction, un appel de fonction est utilisé sur des valeurs d'argument et l'utilisation de l'appel de fonction lui-même est remplacée par sa valeur de retour.

Chaque fonction a une signature de type - les types de ses arguments et le type de son type de retour.

Les fonctions sont inspirées par les concepts de la procédure et de la fonction mathématique.

  • Note: Les fonctions C ++ sont essentiellement des procédures et ne suivent pas la définition exacte ou les règles des fonctions mathématiques.

Les fonctions sont souvent destinées à effectuer une tâche spécifique. et peut être appelé à partir d'autres parties d'un programme. Une fonction doit être déclarée et définie avant d'être appelée ailleurs dans un programme.

  • Remarque: les définitions de fonctions populaires peuvent être masquées dans d’autres fichiers inclus (souvent pour des raisons de commodité et de réutilisation dans de nombreux fichiers). Ceci est une utilisation courante des fichiers d'en-tête.

Déclaration de fonction

Une déclaration de fonction déclare l’existence d’une fonction avec son nom et sa signature au compilateur. La syntaxe est la suivante:

int add2(int i); // The function is of the type (int) -> (int)
 

Dans l'exemple ci-dessus, la fonction int add2(int i) déclare ce qui suit au compilateur:

  • Le type de retour est int .
  • Le nom de la fonction est add2 .
  • Le nombre d'arguments de la fonction est 1:
    • Le premier argument est du type int .
    • Le premier argument sera appelé dans le contenu de la fonction par le nom i .

Le nom de l'argument est facultatif. la déclaration pour la fonction pourrait également être la suivante:

int add2(int); // Omitting the function arguments' name is also permitted.
 

Selon la règle à une définition , une fonction avec une certaine signature de type ne peut être déclarée ou définie qu'une seule fois dans une base de code C ++ entière visible par le compilateur C ++. En d'autres termes, les fonctions avec une signature de type spécifique ne peuvent pas être redéfinies - elles ne doivent être définies qu'une seule fois. Ainsi, ce qui suit n'est pas valide C ++:

int add2(int i);  // The compiler will note that add2 is a function (int) -> int
int add2(int j);  // As add2 already has a definition of (int) -> int, the compiler
                  // will regard this as an error.
 

Si une fonction ne retourne rien, son type de retour est écrit void . S'il ne prend aucun paramètre, la liste de paramètres doit être vide.

void do_something(); // The function takes no parameters, and does not return anything.
                     // Note that it can still affect variables it has access to.
 

Appel de fonction

Une fonction peut être appelée après avoir été déclarée. Par exemple, le programme suivant appelle add2 avec la valeur 2 dans la fonction de main :

#include <iostream>

int add2(int i);    // Declaration of add2

// Note: add2 is still missing a DEFINITION.
// Even though it doesn't appear directly in code,
// add2's definition may be LINKED in from another object file.

int main()
{
    std::cout << add2(2) << "\n";  // add2(2) will be evaluated at this point,
                                   // and the result is printed.
    return 0;  
}
 

Ici, add2(2) est la syntaxe d'un appel de fonction.

Définition de fonction

Une définition de fonction * est similaire à une déclaration, sauf qu'elle contient également le code qui est exécuté lorsque la fonction est appelée dans son corps.

Un exemple de définition de fonction pour add2 pourrait être:

int add2(int i)       // Data that is passed into (int i) will be referred to by the name i
{                     // while in the function's curly brackets or "scope."
                    
    int j = i + 2;    // Definition of a variable j as the value of i+2.
    return j;         // Returning or, in essence, substitution of j for a function call to
                      // add2.
}
 

Fonction de surcharge

Vous pouvez créer plusieurs fonctions avec le même nom mais avec des paramètres différents.

int add2(int i)           // Code contained in this definition will be evaluated
{                         // when add2() is called with one parameter.
    int j = i + 2;
    return j;
}

int add2(int i, int j)    // However, when add2() is called with two parameters, the
{                         // code from the initial declaration will be overloaded,
    int k = i + j + 2 ;   // and the code in this declaration will be evaluated
    return k;             // instead.
}
 

Les deux fonctions sont appelées du même nom add2 , mais la fonction réelle appelée dépend directement de la quantité et du type des paramètres de l'appel. Dans la plupart des cas, le compilateur C ++ peut calculer quelle fonction appeler. Dans certains cas, le type doit être explicitement indiqué.

Paramètres par défaut

Les valeurs par défaut des paramètres de fonction ne peuvent être spécifiées que dans les déclarations de fonction.

int multiply(int a, int b = 7); // b has default value of 7.
int multiply(int a, int b)
{
    return a * b;               // If multiply() is called with one parameter, the
}                               // value will be multiplied by the default, 7.
 

Dans cet exemple, multiply() peut être appelé avec un ou deux paramètres. Si un seul paramètre est donné, b aura la valeur par défaut de 7. Les arguments par défaut doivent être placés dans les derniers arguments de la fonction. Par exemple:

int multiply(int a = 10, int b = 20); // This is legal 
int multiply(int a = 10, int b);      // This is illegal since int a is in the former
 

Appels de fonctions spéciales - Opérateurs

Il existe des appels de fonctions spéciaux en C ++ qui ont une syntaxe différente de name_of_function(value1, value2, value3) . L'exemple le plus courant est celui des opérateurs.

Certaines séquences de caractères spéciales qui seront réduites à des appels de fonctions par le compilateur, comme ! , + , - , * , % et << et beaucoup plus. Ces caractères spéciaux sont normalement associés à une utilisation autre que la programmation ou sont utilisés pour l'esthétique (par exemple, le caractère + est généralement reconnu comme symbole d'ajout à la fois dans la programmation C ++ et dans les mathématiques élémentaires).

C ++ gère ces séquences de caractères avec une syntaxe spéciale; mais, en substance, chaque occurrence d'un opérateur est réduite à un appel de fonction. Par exemple, l'expression C ++ suivante:

3+3
 

est équivalent à l'appel de fonction suivant:

operator+(3, 3)
 

Tous les noms de fonctions d'opérateur commencent par operator .

Alors que dans le prédécesseur immédiat de C ++, C, les noms de fonctions d'opérateurs ne peuvent pas être affectés de différentes significations en fournissant des définitions supplémentaires avec des signatures de types différentes, en C ++, cela est valable. Cacher des définitions de fonctions supplémentaires sous un nom de fonction unique est appelé surcharge d'opérateur en C ++ et constitue une convention relativement commune mais non universelle en C ++.

Préprocesseur

Le préprocesseur est une partie importante du compilateur.

Il édite le code source, coupe certains bits, en change d'autres et ajoute d'autres choses.

Dans les fichiers source, nous pouvons inclure des directives de préprocesseur. Ces directives indiquent au préprocesseur d'effectuer des actions spécifiques. Une directive commence par un # sur une nouvelle ligne. Exemple:

#define ZERO 0
 

La première directive préprocesseur que vous rencontrerez est probablement la

#include <something>
 

directif. Ce qu'il fait est prend tous something et il insère dans votre dossier où la directive était. Le programme hello world commence par la ligne

#include <iostream>
 

Cette ligne ajoute les fonctions et objets vous permettant d'utiliser l'entrée et la sortie standard.

Le langage C, qui utilise également le préprocesseur, n'a pas autant de fichiers d'en-tête que le langage C ++, mais en C ++, vous pouvez utiliser tous les fichiers d'en-tête C.


La prochaine directive importante est probablement la

#define something something_else
 

directif. Cela indique au préprocesseur qu'au fur et à mesure qu'il avance dans le fichier, il doit remplacer toutes les occurrences de something avec something_else . Il peut aussi rendre les choses similaires aux fonctions, mais cela compte probablement comme C ++ avancé.

something_else n'est pas nécessaire, mais si vous définissez something comme rien, alors en dehors des directives du préprocesseur, toutes les occurrences de something disparaîtront.

Cela est utile en raison des directives #if , #else et #ifdef . Le format pour ceux-ci serait le suivant:

#if something==true
//code
#else
//more code
#endif

#ifdef thing_that_you_want_to_know_if_is_defined
//code
#endif
 

Ces directives insèrent le code qui est dans le vrai bit et supprime les faux bits. Cela peut être utilisé pour avoir des morceaux de code qui ne sont inclus que sur certains systèmes d'exploitation, sans avoir à réécrire tout le code.

Le processus de compilation C ++ standard

Le code du programme C ++ exécutable est généralement produit par un compilateur.

Un compilateur est un programme qui traduit le code d'un langage de programmation en une autre forme qui est (plus) directement exécutable pour un ordinateur. L'utilisation d'un compilateur pour traduire du code s'appelle la compilation.

C ++ hérite de la forme de son processus de compilation à partir de son langage "parent", C. Ci-dessous une liste des quatre étapes principales de la compilation en C ++:

  1. Le préprocesseur C ++ copie le contenu de tous les fichiers d'en-tête inclus dans le fichier de code source, génère du code de macro et remplace les constantes symboliques définies à l'aide de #define par leurs valeurs.
  2. Le fichier de code source développé par le préprocesseur C ++ est compilé en langage d'assemblage adapté à la plate-forme.
  3. Le code assembleur généré par le compilateur est assemblé en code objet approprié pour la plate-forme.
  4. Le fichier de code objet généré par l'assembleur est lié aux fichiers de code objet pour toutes les fonctions de bibliothèque utilisées pour produire un fichier exécutable.
  • Remarque: certains codes compilés sont liés entre eux, mais pas pour créer un programme final. Habituellement, ce code "lié" peut également être empaqueté dans un format pouvant être utilisé par d'autres programmes. Ce "paquet de code utilisable et empaqueté" est ce que les programmeurs C ++ appellent une bibliothèque.

De nombreux compilateurs C ++ peuvent également fusionner ou désassembler certaines parties du processus de compilation pour plus de facilité ou pour une analyse supplémentaire. De nombreux programmeurs C ++ utiliseront différents outils, mais tous les outils suivront généralement ce processus généralisé lorsqu'ils sont impliqués dans la production d'un programme.

Le lien ci-dessous prolonge cette discussion et fournit un bon graphique pour vous aider. [1]: http://faculty.cs.niu.edu/~mcmahon/CS241/Notes/compile.html

Visibilité des prototypes et déclarations de fonctions

En C ++, le code doit être déclaré ou défini avant utilisation. Par exemple, ce qui suit produit une erreur de compilation:

int main()
{
  foo(2); // error: foo is called, but has not yet been declared
}

void foo(int x) // this later definition is not known in main
{
}
 

Il existe deux manières de résoudre ce problème: placer la définition ou la déclaration de foo() avant son utilisation dans main() . Voici un exemple:

void foo(int x) {}  //Declare the foo function and body first

int main()
{
  foo(2); // OK: foo is completely defined beforehand, so it can be called here.
}
 

Cependant, il est également possible de "déclarer à l’avance" la fonction en ne mettant qu’une déclaration "prototype" avant son utilisation, puis en définissant le corps de la fonction ultérieurement:

void foo(int);  // Prototype declaration of foo, seen by main
                // Must specify return type, name, and argument list types
int main()
{
  foo(2); // OK: foo is known, called even though its body is not yet defined
}

void foo(int x) //Must match the prototype
{
    // Define body of foo here
}
 

Le prototype doit spécifier le type de retour ( void ), le nom de la fonction ( foo ) et les types de variable de la liste d'arguments ( int ), mais les noms des arguments ne sont PAS requis .

Un moyen courant d’intégrer cela dans l’organisation des fichiers sources est de créer un fichier d’en-tête contenant toutes les déclarations de prototypes:

// foo.h
void foo(int); // prototype declaration
 

et ensuite fournir la définition complète ailleurs:

// foo.cpp --> foo.o
#include "foo.h" // foo's prototype declaration is "hidden" in here
void foo(int x) { } // foo's body definition
 

puis, une fois compilé, liez le fichier objet correspondant foo.o au fichier objet compilé où il est utilisé dans la phase de liaison, main.o :

// main.cpp --> main.o
#include "foo.h" // foo's prototype declaration is "hidden" in here
int main() { foo(2); } // foo is valid to call because its prototype declaration was beforehand.
// the prototype and body definitions of foo are linked through the object files
 

Une erreur de «symbole externe non résolu» se produit lorsque le prototype de fonction et l' appel existent, mais le corps de la fonction n'est pas défini. Celles-ci peuvent être plus difficiles à résoudre, car le compilateur ne signalera pas l'erreur avant la dernière étape de la liaison et ne sait pas à quelle ligne accéder dans le code pour afficher l'erreur.

Algorithmes de bibliothèque standard