Welcome to Bukkit France

Inscrivez-vous maintenant pour profiter d'un accès total à tout le contenu offert par la meilleur communauté Bukkit française ! Une fois inscrit et connecté, vous pourrez contribuez à la communauté en postant vos propres sujets et questions ou en répondant à ceux existants. Vous pourrez aussi customiser votre profil, recevoir des points de réputations, communiquer avec les autres membres via le chat, et plus encore! 

  • Annonces

    • Pskyco

      Bukkit France passe sous Discord !   02/20/16

      Bukkit France est désormais passé sur Discord, au revoir donc notre vieux Teamspeak ! Téléchargez le client et venez nous rejoindre sur notre salon en suivant les instructions suivantes.
      M-à-j du 25/02/2017 : Désormais, seuls les comptes actifs sur le forum se verront donner l'accès au Discord, ce dernier n'est pas une plateforme d'aide de la même manière que le chat.
  • billets
    6
  • commentaires
    20
  • vues
    2542

À propos de ce blog

Le C++ est un langage de programmation fortement typé (c'est-à-dire que tous les types utilisés son connus lors de la compilation), multi-paradigmes, très populaire et multi-plateforme crée par Bjarne Stroustrup. Il est utilisé pour une très large variété d'applications professionnelles, hobbyistes, etc.
Cette série de tutoriels vise surtout à simplifier l'apprentissage du C++ par un développeur venant d'un autre langage, en détaillant au possible chaque aspect.

Billets dans ce blog

while(true);

 

Une variable permet de stocker en mémoire une valeur d'un typé donné. On peut ensuite s'en servir comme bon nous semble.

Rappels de base:


Un octet est égal à 8 bits (sauf dans de la très vieille informatique ou dans de rares domaines de la communication).
Un bit est un chiffre en binaire. C'est-à-dire soit 0, soit 1.
Pour connaître le nombre de possibilités en fonction du nombre de chiffres avec une base donnée, il suffit de faire : basechiffres.
Si on a 32 bits on a donc 232 possibilités soit 4 294 967 296 - un joli paquet.

 

Types courants:

 

Il existe de nombreux types de variables dits "primitifs" en C++. En voici une liste non-exhaustive :

  • bool : C'est un booléen, qui ne peut contenir que true (1) ou false (0). Il est souvent utilisé dans les conditions (voir le prochain chapitre). Attention, il ne mesure pas qu'un seul bit.
  • int : C'est probablement le plus couramment utilisé. Sa taille dépend du type d'architecture cible : Dans le cas du x86, il fait 4 octets (et en x86-64 8 octets). C'est un nombre entier (qui peut être négatif). Il mesure au moins 16 bits. Exemple : 37
  • char : Il est identique au int mais ne mesure généralement qu'un seul octet - attention, cela n'est pas forcément vrai sur certaines architectures exotiques. Il est très souvent utilisé pour la manipulation de texte puisqu'il peut stocker un caractère ASCII (on peut en fait directement assigner un caractère à un char). Exemple : 'a' ou 78. Faites attention : le caractère " permet de délimiter du texte tandis que ' délimite un seul caractère. Vous ne pouvez pas assigner du texte à un char.
  • short : Il est identique au int mais mesure au moins 16 bits, très souvent moins que int. Exemple : 298
  • long : C'est un int de taille supérieure ou égale au int. Il mesure au moins 32 bits.
  • long long : C'est un int de taille supérieure ou égale au long. Il mesure au moins 64 bits. Note: Celui-ci a été introduit par C++11, veillez à utiliser un compilateur récent et à passer -std=c++11 (ou -std=c++14) au compilateur.
  • float : C'est une valeur "flottante". Il permet de stocker des nombres à virgule. Il mesure 4 octets comme le int. Il est préférable de ne l'utiliser que lorsqu'on en a besoin car sa manipulation est plus lente. Exemple : 37.876
  • double : Il est identique au float mais mesure 8 octets. Exemple : 37.876

 

Utilisation & mots-clés:

 

Toutes les variables de ces types peuvent être affichés grâce à std::cout. Il suffit alors de mettre le nom de la variable à la place du "Hello World" que l'on a vu dans le tutoriel.

On peut préfixer les valeurs intégrales (int, char, short) du mot-clé unsigned ce qui fait que les valeurs négatives ne seront plus acceptées. Du coup, cela nous permet d'économiser un bit si on a pas besoin de valeurs négatives (de plus, le compilateur peut mieux pousser ses optimisations). Si vous essayez d'assigner une valeur négative à votre variable unsigned, le compilateur devrait vous avertir.

Le mot clé const permet de rendre une variable non modifiable, par exemple. Dans le cas des primitifs, sa valeur doit donc être assignée lors de la déclaration. Dans cet exemple simple, on place le mot clé const avant le type (voir Approfondir).

#include <iostream>
int main()
{
     float valeurFlottante = 376.84; // Attention! Le nom de cette variable n'est donné qu'à titre d'exemple. Evitez à tout prix de nommer des variables avec des noms peu explicite dans votre code (comme a, b, etc.)
     unsigned int entierPositif = 73;
     char lettreX = 'X';
     std::cout << "La valeur flottante est : " << valeurFlottante << std::endl << "L'entier positif est : " << entierPositif << std::endl << "La lettre est : " << lettreX << std::endl;
     return 0;
}

Testez en ligne!
 

Il est possible de déclarer plusieurs variables à la suite, pour alléger le code visuellement :

int a = 0, b = 3, c = 4; // a, b et c sont tous des int, et on leur donne une valeur de départ
int d, e, f = 4; // Attention : cela ne donne pas la valeur 4 pour d, e et f, mais seulement à f.

 

Portée des variables

 

Une variable déclarée dans un scope anonyme (rappel : délimité par des accolades) ne sera plus accessible en dehors de celle-ci. Par exemple :

#include <iostream>
int main()
{
     { // On a tout à fait le droit de faire ça!
          int maValeur = 5;
     }
     std::cout << maValeur << std::endl; // Erreur : maValeur n'existe pas ici
     return 0;
}

clang++ prévient en effet : main.cpp:7:19: error: use of undeclared identifier 'maValeur'
g++ nous alerte également : main.cpp:7:19: error: 'maValeur' was not declared in this scope

 

Si le compilateur est bien assez intelligent pour éliminer les variables inutilisées, cela peut être une bonne pratique d'utiliser des scopes anonymes quand on peut, notamment dans les grosses fonctions (il faut tout de même mieux diviser les grandes fonctions en plus petites fonctions selon le cas).

 

Valeur des primitifs non initialisés


De plus, une variable que nous définissons mais que nous n'initialisons pas est indéfinie. Cela signifie que sa valeur ne sera pas garantie tant que nous lui donnons pas une valeur.

De ce fait, il ne faut pas lire la valeur de cette variable si l'on ne l'a pas initialisée. Sinon, cela relève du comportement indéfini.

En effet, cette variable aura des chances d'hériter de bouts de mémoire d'un ancien programme ou de bouts de mémoire que le programme a libéré.

#include <iostream>
int main()
{
     int a;
     // La valeur de a ne sera pas forcément zéro!
     a = 3;
     // Maintenant on peut utiliser a.
     return 0;
}

 

Allocation


Quand nous définissons une variable ainsi, cela s'appelle de l'allocation automatique. Dans l'exemple précédent, est un local à la fonction main.
Nous verrons plus tard l'allocation dynamique moderne avec le C++11, grâce à des pointeurs intelligents qui permettent de s'abstraire de la gestion manuelle de la mémoire.
Java utilise presque exclusivement l'allocation dynamique et abstrait la gestion manuelle de la mémoire avec un ramasse-miettes (GC). Si cela rend Java plus performant lors de l'allocation dynamique que le C++, l'allocation automatique en reste plus performante et cela permet d'éviter les coûts inévitables d'un GC.

Nous verrons d'ici peu comment manipuler ces variables.

 

Approfondir (avec des concepts plus avancés) :

 

Taille et capacité d'un type:

La fonction sizeof permet d'obtenir le nombre d'octets qu'utilise un type. Par exemple sizeof(int) retournera la taille du type int. Attention : Pour des pointeurs, par exemple sizeof(float*) mesurera la taille du pointeur plutôt que de la cible.
Vous pouvez inclure le fichier "limits" pour pouvoir connaître de nombreuses informations sur un type donné - par exemple pour la taille maximale d'un float : std::numeric_limits<float>::max(). Documentation

Sur coliru:

  • int : -2147483648 to 2147483647
  • unsigned int : 0 to 4294967295
  • long : -9223372036854775808 to 9223372036854775807
  • unsigned long : 0 to 18446744073709551615
  • long long : -9223372036854775808 to 9223372036854775807
  • unsigned long long : 0 to 18446744073709551615
  • char : -128 to 127
  • unsigned char : 0 to 255
  • short : -32768 to 32767
  • unsigned short : 0 to 65535
  • float : 1.17549e-38 to 3.40282e+38
  • double : 2.22507e-308 to 1.79769e+308

 

Notez qu'il est presque toujours préféré d'utiliser un type plus petit quand on a pas besoin de plus de capacité. Cela aura pour but de réduire l'empreinte mémoire et de potentiellement légèrement accélérer le programme, mais trop se préoccuper de cela est inutile (souvenez vous, l'optimisation prématurée est la cause de tous les maux).

Si il est nécessaire d'avoir des variables de taille fixée (les types normaux ci-dessus ont une taille définie par l'implémentation, variant ainsi entre les machines voire les compilateurs), il est mieux d'utiliser les types du header <cstdint>.

Le type size_t est souvent utilisé pour désigner des tailles (ex. vector::size()). C'est un type non signé de taille définie par l'implémentation.

 

Const, const-correctness et const_cast en C++:

Les const sont plus puissants qu'ils en ont l'air. En effet, si vous construisez un objet ou définissez une référence const, vous ne pourrez utiliser que ses méthodes définies comme const, garantissant ainsi que vous ne modifierez pas l'objet, contrairement aux final de Java. De plus, il est également possible d'avoir une version const et une version normale d'une méthode en C++. Comme dit précédemment, le mot-clé const s'applique à l'objet avant lui (ou après lui s'il se trouve au début). Par exemple :

const int a = 0;
int const b = 0;

Les deux cas précédents sont identiques. Un exemple avec des pointeurs :

int val = 0, val2 = 0;

const int* a = &val; // Pointeur non-const vers un int const
int const *b = &val; // Idem que a
int *const c = &val; // Pointeur const vers un int non-const
int const *const d = &val; // Pointeur const vers un int const
const int *const e = &val; // Idem que d

*a = val2; // Erreur : Assignation de valeur const
a = &val2; // Correct : Assignation d'un pointeur non-const

*c = val2; // Correct : Assignation de valeur non-const
c = &val2; // Erreur : Assignation de pointeur const

*d = val2; // Erreur : Assignation de valeur const
d = &val2; // Erreur : Assignation de pointeur const

On ne peut pas abandonner le const en cours de route de manière implicite:

const int a = 0;
int& b = a; // Erreur: Assigner un 'const int' à une référence de type 'int' élimine le 'const'

Cependant, si on a un objet de départ non-const et une référence vers celui-ci qui est const, il est possible d'utiliser const_cast pour obtenir une référence non-const à partir de cette référence const.

Attention au comportement indéfini, il ne faut surtout pas faire ça si l'objet de départ est const!

int a = 0;
const int& ref = a;
int& b = const_cast<int&>(ref); // Correct
const int a = 0;
const int& ref = a;
int& b = const_cast<int&>(ref); // ATTENTION: Comportement indéfini!

 

Comportements spéciaux:
Quand on dépasse la capacité maximale d'une variable, il se passe ce qu'on appelle un overflow.


Le standard du C++ ne définit pas le comportement d'un overflow sur des types signés (c'est-à-dire qui peuvent avoir une valeur positive ou négative, comme int, char, short).

Il ne faut donc pas baser le fonctionnement de son programme sur de tels overflow, car on ne sait pas ce qui va se passer, et en général les optimiseurs et leurs compilateurs se basent sur le principe que le code de l'utilisateur ne se base pas sur du comportement indéfini. Cela peut paraître agaçant, mais c'est une des puissances (ou faiblesses) du C++ : Cela permet de laisser place à de puissantes optimisations au niveau de compilateur.


Avec les variables unsigned, c'est différent : En cas d'overflow, la variable revient à 0, cette fois-ci le standard le définit bien!

 

Notez qu'il existe des cas comme ceux-ci : Utiliser l'opérateur binaire << sur un entier négatif cause un comportement indéfini, utiliser l'opérateur binaire >> sur un entier négatif cause un comportement défini par l'implémentation.


Pour les types flottants, l'overflow provoque un comportement indéfini surtout car le fonctionnement des float est plus compliqué (et serait inutilement complexe à implémenter de manière standardisée pour diverses raisons).

while(true);

Une condition peut être soit vraie, soit fausse.
Par exemple, la condition 2 < 3 est vraie, mais la condition 5 < 2 sera fausse.

Attention : Pour vérifier si un nombre est égal à un autre, on utilise == et non pas =, qui est l'opérateur d'assignation (pour assigner une valeur à une variable) et non pas celui de comparaison.

Il existe la structure conditionnelle if en C++. Elle permet de vérifier une condition (= tester) et si elle est vraie, alors du code sera exécuté. Il est possible de la compléter avec else, qui exécute du code dans le cas où la condition est fausse, ou else if, qui permet de vérifier une autre condition dans le cas où la première est fausse.
Pour délimiter le code à exécuter si la condition est vraie, on utilise soit des accolades, soit rien si on veut n'exécuter qu'une seule instruction (cela ne compte pas autres conditions et boucles).

#include <iostream>

int main()
{
    int valeur = 2;
  
    if (valeur < 7)
    {
        std::cout << valeur << " est bel et bien inférieur à 7!" << std::endl;
    }
    else if (valeur == 7)
    {
        std::cout << "La valeur est égale à 7" << std::endl;
    }
    else
    {
        std::cout << valeur << " est inférieur à 7." << std::endl;
    }
  
    return 0;
}
#include <iostream>

int main()
{
    int valeur = 2;
  
    if (valeur < 7)
        std::cout << valeur << " est bel et bien inférieur à 7!" << std::endl;
    else if (valeur == 7)
        std::cout << "La valeur est égale à 7" << std::endl;
    else
        std::cout << valeur << " est inférieur à 7." << std::endl;
  
    return 0;
}

Attention, deux erreurs très courantes chez les débutants (et pas que) :

  • On ne rajoute jamais de point-virgule après une structure conditionnelle (et plus tard, pareil avec les boucles)!
#include <iostream>

int main()
{
    int valeur = 2;
  
    if (valeur > 7); // Surtout pas ça! Cela équivaut au code ci-dessous...
        std::cout << valeur << " est supérieur à 7!" << std::endl;

  
    return 0;
}
#include <iostream>

int main()
{
    int valeur = 2;
  
    if (valeur > 7)
    {
        // Mettre un point-virgule après une condition, ça équivaut à dire : si quelque chose, alors ne rien faire.
        // Ce n'est pas du tout ce qu'on veut! Le pire dans tout ça, c'est que le code en dessous va être toujours exécuté.
        // En effet, rien n'empêche de mettre du code dans une scope "sauvage".
    }

    {
        std::cout << valeur << " est supérieur à 7!" << std::endl;
    }

  
    return 0;
}
  • Quand on ne met pas de scope, on ne peut pas mettre deux instructions à la suite!
#include <iostream>

int main()
{
    int valeur = 2;
  
    if (valeur > 7)
        std::cout << valeur << " est supérieur à 7!" << std::endl; // Cela ne va être exécuté que lorsque la valeur est supérieure à 7...
        std::cout << "Cette valeur est vraiment supérieure à 7!" << std::endl; // Ce code va être exécuté peut importe quelle est la condition! Une faille majeure dans OSX était justement due à ce genre d'erreur. Faites attention!
  
    return 0;
}

Approfondir :

Si on utilise un quelconque nombre en tant que condition, la condition sera fausse si nombre == 0 et vraie sinon.
Pour vérifier si un tel nombre est non nul (non égal à zéro), nous avons complètement le droit de faire if (nombre) et c'est couramment fait. Par soucis de clarté, j'évite de faire if (!nombre) pour vérifie si le nombre est nul. Sachez que cela ne cause aucun problème cependant, mais je préfère garder mon code explicite au possible.

 

Les opérateurs logiques nous permettent de vérifier plusieurs conditions à la fois dans une seule boucle if.

En voici la liste :

  • || signifie OU. Par exemple, if (valeur < 3 || valeur > 8) permet de vérifier si la valeur est inférieure à 3 OU supérieure à 8.
  • && signifie ET. Par exemple, if (valeur1 == 7 && valeur2 == 3) permet de vérifier si valeur1 est égale à 7 ET si valeur2 est égale à 3.
  • ! signifie NON. Cet opérateur permet d'inverser la valeur d'un booléen (ou de rendre un nombre non égal à 0 égal à 0 (pas zéro => 0) ou un nombre égal à zéro égal à 1 (0 => 1).
    Le C++ ne fournit pas d'opérateur OU EXCLUSIF logique (qui serait ^^) mais !a != !b permet d'obtenir le même résultat, c'est-à-dire que la condition sera vraie seulement si a est vrai mais pas b.
    Vous pouvez englober cela dans une simple fonction :
    inline bool xor(const bool& a, const bool& b)
    {
    	return (!a) != (!b);
    }

    Au passage : inline informe au compilateur qu'on souhaite que la fonction soit directement intégrée au code. C'est bien pour du petit code ou du code exécuté peu de fois pour gagner en performances en éradiquant le temps perdu par l'exécution de la fonction, mais peut ralentir et grandement alourdir le code binaire résultant pour de larges fonctions ou des fonctions appelées à divers endroits du code. Ce n'est pas une garantie et cela n'arrive en général que lorsqu'on active les optimisations (-O3 par exemple).
    const bool& passe les deux variables par référence constante pour permettre au compilateur de pousser ses optimisations (ici ça ne servirait que si l'inline n'est pas possible).


On peut englober une condition de parenthèses pour obtenir une meilleure clarté du code ou pour palier la priorité des opérateurs, par exemple : if ((valeur1 < 3) && ((8 + valeur2) > 7)).

while(true);

Un grand classique dans les tutoriels de programmation : Le Hello World.
Il consiste simplement à afficher un message grâce à un langage de programmation, souvent en console.

 

Il y a plusieurs moyens de faire un "Hello World" en C++. En voici un moyen courant :

#include <iostream>
int main()
{
  std::cout << "Hello, world!" << std::endl;
  return 0;
}

Testez en ligne!

Décortiquons donc :

#include <iostream>

#include est ce que l'on appelle une directive de préprocesseur. C'est la première chose dont le compilateur se charge. iostream est le fichier que nous voulons inclure. Ici, iostream permet de manipuler des flux d'entrée et de sortie. Il nous fournira cout qui signifie "character out". Il nous permet de sortir du texte vers la console. Les chevrons (< >) qui délimitent iostream signifient ici que nous voulons chercher quelque chose dans une bibliothèque "globale", qui n'est donc pas locale au projet. Cela compte la bibliothèque standard du C++ (donc iostream) et éventuellement d'autres bibliothèques dépendantes du système ou installées manuellement par l'utilisateur. Nous verrons plus tard que pour importer un fichier crée manuellement pour un projet par l'utilisateur, il faut utiliser des guillemets (" ").

 
int main()

On définit ici une "fonction", main. C'est le point d'entrée de notre programme, c'est-à-dire c'est la première partie de notre code qui sera appelée (exécutée) dans notre programme. La plupart des compilateurs oblige main() a renvoyer un "int", c'est-à-dire une valeur entière (voir chapitre sur les variables), qui correspond en général à 0 si l'exécution s'est bien passée ou à autre chose si un problème est intervenu (et dans ce cas la valeur renvoyée est souvent le code d'erreur).

 
{ }

Les accolades délimitent ce qu'on appelle une "scope". Ici la scope définit ce que doit contenir la fonction. On peut les placer de manière "sauvage" à l'intérieur d'une fonction par exemple sans contexte afin de définir la portée de variables données.

 
std::cout << "Hello, world!" << std::endl;

Voyons donc. Voici notre fameux "cout". C'est le flux de sortie vers la console. Les deux chevrons pointant vers la gauche délimite les éléments à envoyer dans le flux - Pour cout on peut donner des nombres, du texte, un peu de tout... Puisque cout est un flux de sortie, on les place dans ce sens. Pour cin que l'on verra plus tard, on les place dans l'autre sens (>>). Vient maintenant notre "Hello, world!". C'est une sorte de tableau de caractères. Nous y reviendrons plus tard. endl permet de faire un saut de ligne. Cependant il va en réalité plus loin : Il attend que tout ce qu'on lui a envoyé plutôt finisse d'être "stocké" par la console. Ce n'est pas spécialement grave sauf si on affiche énormément de choses dans la console. Cela aide pour le débogage.

 
std::

En fait, std est un espace de noms utilisé par la bibliothèque standard. Un espace de noms (ou namespace en anglais) est comme son nom l'indique un espace où l'on peut placer un peu tout ce que l'on veut : Variables, classes, fonctions. Ceci de un, pour avoir plus de clarté dans le code et mieux savoir d'où vient quelque chose que l'on utilise, mais de deux, surtout pour éviter les conflits. Par exemple, si une bibliothèque fournissait une fonction void poney() et qu'une autre bibliothèque fournissait aussi void poney(), alors il y aurait conflit et le compilateur ne saurait pas laquelle utiliser. Grâce à un espace de nom, on pourrait placer void poney() de la première bibliothèque dans un espace de noms lib1 et l'autre dans un espace de noms lib2.

 

cout et endl sont stockés dans l'espace de noms std. Pour y accéder nous devons juste placer le nom de l'espace de noms puis deux fois deux points pour pouvoir accéder à eux. :: est un opérateur de résolution de scope. Du coup on a bien std::cout et std::endl.

 

Nous aurions également pu utiliser ceci : using namespace std; Il n'est pas recommandé de placer cette ligne "sauvagement" dans le fichier, hors de toute fonction, car cela casse l'intérêt d'avoir un espace de noms. Néanmoins cela aurait pu nous permettre de s'abstenir d'utiliser std:: et de rajouter cout et endl directement.

 
return 0;

Puisque notre fonction main doit renvoyer une valeur, nous le faisons ici. Comme je l'ai dit tout à l'heure, 0 signifie que le programme, en général, s'est bien exécuté.

 


Maintenant que nous avons bien décortiqué un simple hello world, nous pouvons passer au chapitre sur les variables!

while(true);

Note : Ce blog est une réécriture du tutoriel sur le C++ en cours que j'ai créée il y a quelques semaines. Il ne sera plus mis à jour et ce blog propose des chapitres bien plus étoffés, clairs et accessibles. Je proposerai des hors-séries à la J&JJS plus tard sur, par exemple, Arduino, des bibliothèques en particulier ou quelque chose d'intéressant lié au C++.

Le C++ est un langage de programmation fortement typé (c'est-à-dire que tous les types utilisés son connus lors de la compilation), multi-paradigmes, très populaire et multi-plateforme crée par Bjarne Stroustrup. Il appartient au domaine public et en conséquence tout le monde peut utiliser, implémenter, modifier le standard du C++ quel qu’en soit son utilisation. Il est utilisé pour une très large variété d'applications professionnelles, hobbyistes, etc.
Celui-ci hérite directement du langage C mais fournit des fonctionnalités bien plus haut niveau tout en restant rétrocompatible (en général) avec ce langage.

 

Soit - ce langage est bien plus complexe, mais il n'est pas si déroutant qu'il n'en a l'air pour un développeur Python, Java ou de n'importe quel autre langage (par contre, venant d'un développeur en assembleur, ça serait quand même plus surprenant :)). Ce tutoriel est plus orienté vers un développeur lambda qu'à un débutant voulant s'initier à la programmation (et honnêtement, commencer par du C++ lorsque l'on ne s'y connaît pas est une très mauvaise idée).

 

Il existe de nombreuses raisons de pourquoi le C++ est puissant et largement utilisé. En voici quelques exemples :

  • Les compilateurs disponibles font partie des meilleurs qui existent sur le marché et proposent des optimisations très poussées, égalant et battant la JVM dans un très grand nombre de cas.
    La compilation consiste, par définition, de "transformer" du code d'un langage X vers un langage Y. Dans le cas du C++, ce sera souvent transformer du C++ (forcément) vers du code machine.

    g++ est le compilateur le plus répandu sur le marché. Ses optimisations sont très bonnes et il est activement mis à jour. La gestion préliminaire des standards à venir est assez rapide.
    clang++ est un nouveau compilateur en vogue basé sur LLVM et développé par Apple (incroyable, hein :)) qui évolue extrêmement vite et qui commence à battre g++ au niveau de la qualité des optimisations. C'est certainement le compilateur qui propose les fonctionnalités de standards à venir le plus rapidement.
    MVSC++ est un compilateur développé par Microsoft. Il n'est pas mauvais mais ses optimisations sont bien moins poussées que pour g++, clang++ et ICC et il a beaucoup de retard par rapport aux standards. De plus, il ne fonctionne que sous Windows. Il est fortement lié à l'IDE Visual Studio également de Microsoft.
    ICC est un compilateur développé par Intel. La capacité de ses optimisations devançait de loin celles de g++ et clang++, mais l'écart tend à se marginaliser, même si il demeure dans certains cas (vectorisation/parallélisation) nettement supérieur aux compilateurs cités précédemment.
     
  • Parce que le C++ est multi-paradigmes, une seule "méthode" de programmation n'est pas imposée ou sur-utilisée (pas comme le Java par exemple avec la POO) : Il est aussi bien orienté objet que générique ou fonctionnel.
     
  • La POO reste néanmoins un concept très puissant en C++. En effet, elle propose l'héritage multiple, l'héritage virtuel (qui permet de gérer les cas complexes comme l'héritage en diamant), le polymorphisme (évidemment), ...
     
  • Le langage est fortement typé. Bien que son statut de qualité puisse être mis en débat, cette capacité est très utile pour, de un, permettre la compilation (et avec toutes les optimisations qui vont avec), et de deux, pour une plus grande clarté du code ('1' + 1 est bel est bien fonctionnel en javascript, ce qui n'est pas vraiment prévisible)
     
  • La gestion de la mémoire est "manuelle", ce qui permet de s'abstenir d'un Garbage Collector (bien que cela reste possible d'en implémenter un; le C++ par nature le permet et le C++11 l'a encore facilité - il existe déjà des bibliothèques pour y parvenir); exit donc une charge ajoutée lors de l'exécution, et l'on peut prédire lorsqu'un objet sera détruit.
    Une variable allouée statiquement (c'est-à-dire sans utilisation de new et de malloc) a une durée de vie précise (ce qui permet l'utilisation de l'idiome RAII de manière précise) tandis qu'une variable allouée dynamiquement avec new (et d'où on récupère un pointeur cru, *) ne sera jamais libérée sauf si l'on utilise delete.
    Mais les pointeurs intelligents du C++11 permettent de simplifier la gestion de la mémoire dynamique pour éviter les fuites de mémoire. En effet, ils permettent de gérer un pointeur C intelligemment pour, à quasi coup sûr, empêcher les memory leak et contrer très efficacement le manque de GC.
     
  • Bien que des benchmark mettent des fois nez-à-nez les performances de la JVM et du C++ (ou font largement gagner la JVM en ayant bien pensé à saboter les résultats en désactivant les optimisations pour le C++), le C++ ne fait pas l'objet (jeu de mot non voulu) d'une abstraction excessive ce qui permet de réaliser des optimisations impossibles dans des langages (très) haut niveau ce qui place le C++ souvent bien au dessus de Java et de quasiment tous les autres langages en conditions réelles pour peu qu'on optimise son code.
     
  • Le standard du C++ est en constante évolution. Le C++17 (ou C++1z) est en préparation, et la dernière révision majeure, le C++11 (dont j'ai bien venté les mérites ici ;)), a permis d'améliorer encore plus le langage et d'étoffer la bibliothèque standard - pour citer Bjarne Stroustrup, "Surprisingly, C++11 feels like a new language".
    Avantage non-négligeable, de plus, la plupart des compilateurs modernes permettent le choix du standard avec l'argument -std (-std=c++11, std=c++14, std=c++1z...) ce qui permet d'avoir les bénéfices d'un compilateur complètement à jour sans avoir à modifier son code si de (très) rares modifications du standard forçaient à changer quelques lignes de code.
     
  • Le C++ est largement multi-plateforme : Il existe bien sûr des compilateurs pour le x86 (certainement l'architecture de ce sous quoi tourne votre machine), mais également pour ARM (téléphones, télévisions, raspberry pi, de nombreuses consoles de jeu surtout portables...), AVR (Arduino Uno) et encore d'autres (PowerPC - Gamecube, Wii, Wii U, PS3 et Xbox 360; SPARC), mais même du JavaScript utilisable pour du web avec emscripten!
     
  • Les utilisations du C++ sont diverses est variées. Bien sûr, on peut créer des applications pour bureau (avec pour bibliothèque de GUI GTK+, Qt, ...), mais aussi pour téléphone, pour en partie le front-end ET back-end web (emscripten, CppCMS), de l'embarqué (Arduino et diverses autres microcontrôleurs)
     
  • Bien que plus minimaliste que celle du Java par exemple, la bibliothèque standard du C++ est très rigoureusement gérée par des développeurs expérimentés et les fonctionnalités sont retournées de toutes les manières avant d'être votées par les comités du C++ et d'être intégrées.


Je vous ai mis l'eau à la bouche? Alors continuons!

 

Sommaire :

while(true);

Un IDE (EDI en français, Environnement de Développement Intégré) est un programme qui regroupe trois fonctionnalités clés pour développer un programme : Éditeur, compilateur, débogueur.
L'éditeur est tout simplement où nous allons écrire notre code.
Le compilateur permet de "métamorphoser" notre code C++ en code machine que nous pourrons directement lancer. En général, il nous permet d'optimiser le code machine très efficacement.
Le débogueur permet comme son nom l'indique d'aider à la résolution de bugs. Il nous permet d'interrompre le code à un endroit précis afin d'examiner ce qu'il se passe dans X situation (variables, ...)

 

Voici une liste non exhaustive des IDE disponibles sur le marché :

  • Code::Blocks est l'IDE le plus connu chez les débutants en C++ (probablement avec VS). Sous Windows, pensez à télécharger le troisième exécutable comprenant MinGW, sinon vous ne pourrez pas compiler votre code C++ ce qui serait assez gênant. Il est gratuit mais souffre de nombreuses lacunes : Son auto-complétion est mauvaise, de même pour le refactor, et les thèmes sont très laborieux à utiliser. Néanmoins il reste facile à prendre en main et suffira à tout développeur qui ne dépende pas trop de son IDE.
  • CLion est un IDE développé par JetBrains (même développeur qu'IntelliJ que les développeurs de Java devraient connaître) très puissant et que j'utilise actuellement. Il dispose d'un thème dark pour le plus grand plaisir de votre rétine, il est bien personnalisable, son auto-complétion et le refactor sont tous deux très bons, et le débogueur, gdb, est très bien intégré. Comparé à Code::Blocks, il peut être plus compliqué à prendre en main. Si vous êtes étudiant, ou même lycéen ou collégien, vous devriez pouvoir l'obtenir gratuitement en remplissant le formulaire en prenant une photo de votre certificat de scolarité (reçu au début de l'année normalement). Attention, il faudra renouveler la licence chaque année. Sinon, vous pouvez utiliser la version Early Access qui est gratuite, mais instable est pas toujours disponible, et doit être mise à jour souvent. C'est celui que j'utiliserais au long du tutoriel.


Autres IDEs disponibles :

  • Visual Studio est un IDE développé par Microsoft qui souffre de nombreuses lacunes : Son compilateur, MVSC++, est quasiment le seul utilisable sans passer plusieurs heures à essayer d'utiliser g++ ou autre; il n'est disponible que sous Windows et il est très lourd (comptez plusieurs gigaoctets à télécharger). Cependant il n'y a pas que du mauvais - Sans hésiter, son auto-complétion bat celle de C::B (mais pas celle de CLion), il est quasiment aussi facile à prendre en main et il dispose de pas mal de fonctionnalités intéressantes (par exemple, le profilage et le débogueur bien intégrés).
  • CodeLite est un IDE que je n'ai pas vraiment eu l'occasion d'essayer, mais qui semble avoir de très bons retours sur sa prise en main et sa fonctionnalité. Essayez par vous-mêmes.
  • CDT est un plugin pour Eclipse (que là encore les développeurs de Java connaissent bien) qui permet de transformer Eclipse en un véritable IDE C++ relativement puissant. Malheureusement, j'ai eu des problèmes de compilation avec donc je n'ai jamais retenté le coup.
  • NetBeans est là encore et encore un IDE que les développeurs de Java connaissent bien, qui bien que sous ses allures de machine à gaz (et ça en est le cas, il est difficile à prendre en main), renferme bien un logiciel peaufiné dans le détail. Le refactor est correct et l'auto-complétion est assez bonne.
  • Qt Creator est un IDE développé pour simplifier l'utilisation de la très bonne bibliothèque C++ Qt en proposant une interface d'édition de GUI WYSIWYG assez pratique et efficace. La mise en place du compilateur a été un peu laborieuse pour moi et je ne l'ai pas longuement utilisé (et cela remonte à quelques années) mais il a de très bons retours.


Installation et configuration de CLion :

Révélation

Commencez d'abord par télécharger le programme Early Access pour avoir une version plus ou moins gratuite (voir lien ci-dessus) pour la plateforme souhaitée.
Quand CLion s'ouvrira, il vous proposera de configurer rapidement l'IDE, avec le thème et quelques recommandations de plugins.

 

Instructions spécifiques pour Linux :

Révélation

Sous Linux, vous devez installer g++ et tout ce qui va avec. Sous Debian, Ubuntu et Mint, il suffira d'exécuter dans un terminal

 


sudo apt-get install build-essential

 

 

Sc410nn.png

Si ceci s'affiche, alors vous avez déjà tout d'installé. Pour d'autres distributions, il existe très certainement des paquets similaires. Référez-vous aux repos de votre distribution. Vous devez maintenant extraire CLion et le placer où vous voulez. Naviguez dans son répertoire, puis dans le dossier bin. Pour lancer CLion, essayez de cliquer sur start.sh et choisissez exécuter si cette option vous est proposée. Si seulement un éditeur de texte apparaît, ouvrez un terminal, naviguez jusqu'au même dossier (avec la commande cd) et tapez ensuite :

 


chmod +x ./start.sh./start.sh

Sous Linux, en général, vous aurez le choix pour un thème GTK+. Sélectionnez-le pour intégrer au mieux l'IDE à votre thème, cependant notez que pour ma part mon thème sombre n'a pas trop été apprécié par CLion. Dans ce cas-ci, autant utiliser "Darcula".

 

Par défaut, le compilateur g++ sera utilisé. Cependant vous pouvez installer clang++ simplement :

 


sudo apt-get install clang

Vous pouvez alors utiliser ce compilateur très facilement en ajoutant dans le fichier CMakeLists.txt (voir plus bas) :

 


set(CMAKE_C_COMPILER "clang")set(CMAKE_CXX_COMPILER "clang++")

 

 

Instructions spécifiques à Windows :

Révélation

Sous Windows, vous devrez télécharger et installer MinGW en suivant ce tutoriel.
Ensuite, lancez CLion, configurez-le comme vous le souhaitez et allez dans le menu File, puis Settings. Dans la catégorie "Build, Execution, Deployment", allez dans Toolchains et cochez "Use specified MinGW" (de mémoire), appuyez sur les trois points et spécifiez le chemin jusqu'à MinGW (en général, C:\MinGW). Laissez les autres paramètres.
Attention : Il semble qu'Avast provoque des problèmes avec CLion quand on essaie de lancer un exécutable que l'on a compilé. Désactivez-le ou ajoutez le dossier de CLion en exception.

 

Je n'ai pas de mac donc je ne saurais pas aider dans ce cas-ci, alors débrouillez-vous ou utilisez une alternative :P. Vous pouvez utiliser XCode qui a l'air d'être un IDE correct. Il utilise clang++ qui est un bon compilateur.

 

L'IDE est fin prêt! Créons un projet.
Allez dans le menu "File" puis "Create project". Dans "Project name", donnez le nom voulu à votre projet. Pour ma part, ce sera "cpptut".


or8lkGz.png


Vous avez deux onglets d'ouvert : Le fichier principal (main.cpp) et CMakeLists.txt qui nous permet de configurer CMake, qui s'occupe pour nous de gérer le projet, les différentes cibles de compilation, etc.
CLion nous a généré ces deux fichiers pour démarrer simplement. On ne devrait pas avoir à faire de modifications dans le CMakeLists.txt et le main.cpp est un hello world que nous pourrons essayer de compiler et de lancer pour voir si CLion fonctionne bien.
Cliquez maintenant sur le bouton "build" à gauche du bouton d'exécution et de "Build All" (par défaut) qui se trouve en haut à droite de l'écran. Cliquez ensuite sur le bouton d'exécution qui se trouve à la droite de "Build All" et de ce bouton Build.
Ce menu s'affiche alors :

 

 

 


QEUuEr5.png


Changez "Configuration" pour mettre "Release" et "Executable" pour le nom de votre projet (pour moi, cpptut).
Cliquez ensuite sur Run et vous devriez voir un Hello World dans la console en bas.

QpEC3sH.png


Si ça n'en est pas le cas, dites donc le problème en commentaire.

 

Sinon, l'IDE fonctionne bel et bien!