La Foire Aux Questions de fr.comp.lang.c++ (Copyright (C) 1998 -- 2001 Gabriel Dos Reis) -------- [0] Introduction [1] Généralités [3] Les objets [7] Les déclarations [9] Les classes [14] Les génériques [21] Les chaînes de caractères [27] Les flux d'entrée sortie -o-o-o-o-o-o-o-o-o-o-o-o-o- 0. Introduction _________________________________________________________________ 0.1. J'ai appris, grâce à un informateur sûr dont je tairai le nom, l'existence de fr.comp.lang.c++. Qu'est-ce que c'est ? fr.comp.lang.c++ n'est pas une conspiration galactique mise en place par le gouvernement. C'est un forum de discussion, non modéré, d'expression francophone, portant sur le langage de programmation C++. Non modéré ne signifie pas que l'on doit y discuter de la pluie et du beau temps. Ce qui nous amène au second point : _________________________________________________________________ 0.2. Comment retrouver les discussions passées ? Les messages postés dans le groupe fr.comp.lang.c++ sont archivés. Ils peuvent être consultés en utilisant par exemple http://groups.google.com. _________________________________________________________________ 0.3. Y a-t-il des équivalents internationaux de fr.comp.lang.c++ ? Oui. Les principaux sont : * comp.lang.c++ (groupe anglophone non modéré) * comp.lang.c++.moderated (groupe anglophone modéré) * comp.std.c++ (groupe anglophone modéré) _________________________________________________________________ 0.4. Au fait, à quoi sert ce document que je suis en train de lire ? Ce document ne sert pas seulement à occuper le temps libre. Il essaie de répondre (succinctement) aux questions fréquemment posées sur le forum fr.comp.lang.c++, d'indiquer des pointeurs vers des ressources C++ disponibles sur le Réseau. Les informations qu'il contient trouvent leurs origines dans des discussions menées (et articles postés) sur le forum fr.comp.lang.c++ (ou ses cousins internationaux). Une liste complète des contributeurs n'est pas disponible. Néanmoins l'auteur tient à leur exprimer sa profonde gratitude, en particulier à : Stéphane Bailliez, James Kanze, Michel Michaud, Jean-Marc Bourguet, Loïc Joly, Laurent Laporte, Alain Naigeon, ... _________________________________________________________________ 0.5. La FAQ de fr.comp.lang.c++ est-elle une référence sûre ? Ce document n'est pas une bible. Toute opinion exprimée dans cette FAQ ne reflète pas forcément les conceptions de l'auteur ou celles de la communauté C++. Cependant Il a été porté une attention particulière à la mise à jour des informations indiquées. Mais aucune garantie n'est expressément fournie quant à leur exactitude. _________________________________________________________________ 0.6. Je dispose d'une information ultra-confidentielle, classée secret-défense. Mais j'aimerais la partager avec la communauté C++ francophone et l'ajouter à cette FAQ. Comment faire ? Pour tout ajout, commentaire et remarque, me contacter par courrier électronique : Gabriel.Dos-Reis@cmla.ens-cachan.Fr. _________________________________________________________________ 0.7. Je trouve la FAQ de fr.comp.lang.c++ hyper-pratique et top-géniale ; pour rien au monde je ne voudrais en détenir une version dépassée. Comment me tenir à jour ? La version la plus récente, au format HTML, se trouve ici : http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/. La même version de ce document au format texte est également disponible sur le site ftp ftp://ftp.cmla.ens-cachan.fr/pub/c++/. _________________________________________________________________ 0.8. Ce document est couvert par un droit d'auteur _____________________________________________________________________ Redistribution for profit, or in altered content/format prohibited without permission of the author. Redistribution via printed book or CDROM expressly prohibited without consent of the author. Any other redistribution must include this copyright notice and attribution. _____________________________________________________________________ _________________________________________________________________ -o-o-o-o-o-o-o-o-o-o-o-o-o- _________________________________________________________________ 1. Généralités Cette section fournit des informations d'ordre général, allant de la nétiquette aux ressources disponibles sur le Réseau. _________________________________________________________________ 1.1. Y a-t-il une nétiquette sur fr.comp.lang.c++ ? Il existe sur fr.comp.lang.c++, comme dans toute communauté, des règles à observer pour le fonctionnement harmonieux du groupe. Par exemple ce forum est doté d'une charte (postée toutes les quinzaines sur le groupe) que tout nouveau venu est invité à lire et à méditer. Cette section rassemble un embryon de suggestions (de bon sens) dans le but d'augmenter le rapport signal/bruit du forum fr.comp.lang.c++. 1.1.1. Je ne comprends pas : qu'est ce que le rapport signal/bruit ? Le rapport signal/bruit correspond au ratio du nombre total de messages postés au nombre de messages hors sujet. Autrement dit, si sur 100 messages postés il est compté 90 messages hors-sujet alors le rapport signal/bruit est de 10/9, environ 1.111. S'il n'y a que 10 messages hors-sujet alors ce rapport de 10. Dans un monde parfait ce rapport devrait être infini (100/0). Le but est de s'approcher de cette perfection. L'intérêt d'avoir un ratio aussi élevé que possible est de permettre aux lecteurs de lire et de répondre aux bons messages et de ne pas être submergés par les messages hors-sujet. Il convient d'être réaliste : les personnes pouvant répondre aux questions ne sont pas des robots, ce sont des êtres humains ayant des contraintes temporelles. En ne cédant pas à votre pulsion et en respectant des règles élémentaires, vous permettrez à ces personnes de prendre 30 secondes pour lire votre (bon) message plutôt que d'en perdre 30 à lire un mauvais message et donc de ne pas prendre ces 30 secondes pour potentiellement répondre à un bon message : peut-être le vôtre. 1.1.2. Aha, j'ai compris. Mais comment je sais si ma question n'est pas hors sujet ? Ce forum est dédié au langage C++. C'est à dire que l'on discute en particulier de l'utilisation du langage, de conception, d'implémentation, de l'utilisation des méthodes et classes correspondant au C++ standard ainsi qu'à sa bibliothèque standard. En clair si vous avez des questions sur virtual, template, stream, destructeur, constructeur, etc.. ce newsgroup est la bonne place. La question doit être formulée de manière indépendante de la plate-forme. Autrement dit si vous programmez sous Unix, DOS, Windows, BeOS, etc... votre question doit pouvoir s'appliquer. fr.comp.lang.c++ n'est donc pas dédié à un compilateur particulier (Visual C++, Borland C++, Borland C++ Builder, GCC, DJGPP, ...) ni à un OS particulier (Windows NT/95/3.x, Linux, Solaris, DOS, BeOS...). Il existe des newsgroups dédiés à cela. [ Ajouter une note explicative à cette assertion pour ne pas offrir l'opportunité d'une interprétation conflictuelle avec la charte du groupe. ] Voici un exemple de newsgroups et des questions associées. * fr.comp.lang.c * Sujet: comment j'utilise printf ? * Sujet: comment j'ouvre un fichier avec fopen ? * Sujet: quelle est la syntaxe de malloc ? * Sujet: comment je déclare un tableau de pointeurs de fonctions retournant des pointeurs de fonctions retournant des pointeurs sur des caractères ? * Sujet: que signifie char* ? fr.comp.ms-windows.programmation microsoft.public.fr.vc microsoft.public.vc.* (newsgroups anglophones avec découpage plus profond) * Sujet: Problème de CString * Sujet: Problème avec les MFCs * Sujet: Comment je fais pour faire ... avec l'appwizard * Sujet: MSDN en Fr * Sujet: Visual C++/Exécutable * Sujet: Boutons transparents avec Visual C++ * Sujet: Problèmes sous Visual C+ avec playsound comp.ms-windows.programmation borland.public.cppbuilder.* (newsgroups anglophones avec découpage plus profond) * Sujet: Site sur c++ builder * Sujet: Besoin d'aide sur Builder c++ * Sujet: Réseau et c++ builder * Sujet: Borland c++ builder 4 * Sujet: AppBar en borland c++ builder ? fr.rec.jardinage.bonsai * Sujet: quelle est la fréquence de coupe des feuilles pour mon bonsaï nain ramené de Kyoto ? Il existe plus de 30000 newsgroups. Il y a donc de fortes chances que vous trouviez le newsgroup adapté à votre problème particulier. Dans tous les cas avant de poster un message, il est conseillé de lire le newsgroup pendant quelques jours afin de sentir la température et de consulter la FAQ associée. 1.1.3. Comment persuader fr.comp.lang.c++ de faire mon devoir à ma place ? Vous ne devez sûrement pas avoir peur du ridicule. Il est inutile d'essayer. Les sujets proposés comme devoirs d'écoles sont connus comme le loup blanc et il est inutile d'afficher votre fainéantise et votre manque d'investissement personnel en public. 1.1.4. Comment puis-je éviter les erreurs fréquemment commises ? Il est souhaitable de ne pas * « crossposter » une question dans un nombre important de forums en espérant avoir au moins une réponse. Mieux vaut choisir le meilleur groupe adapté à la question. * écrire : « SVP, répondez-moi par mail car d'habitude, je ne lis ce forum par manque de temps. » Si vous n'avez pas le temps de lire ce forum, comment pouvez-vous imaginer que le forum a le temps de répondre à vos questions ? * poser des questions déjà traitées dans la FAQ. Toujours lire en premier la FAQ : vous gagnerez du temps. * inclure dans sa signature une adresse e-mail invalide. 1.1.5. Toto vient de poser une question traitée dans la FAQ. Que dois-je faire ? Ne pas répondre à la question. Mais inviter, avec politesse et conviction, Toto à lire la FAQ. Suggestion : Subject: La question est dans la FAQ (était: HELP HELP HELP) > L'interruption 21 ne marche pas dans mon programme !!!! HELP !!! Cette question est déjà traitée dans la FAQ qui se trouve ici : http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/ 1.1.6. Que dois-je mettre dans le champ « Subject: » ? De préférence, une description précise et concise du propos de votre message. * Médiocre : « AIDEZ-MOI » * Médiocre : « Problème avec C++ » * Médiocre : « SEX, MONEY, SEX » * Bien : « Problème avec operator= virtuel » 1.1.7. J'ai un problème avec un code défectueux. Y a-t-il des démarches particulières à suivre pour le poster sur le forum ? Pas particulièrement, à part le choix d'un champ « Subject: » assez suggestif, et l'observation des remarques de bon sens suivantes : * inclure un code qui peut compiler (éviter void f() {...}) * inclure un code complet avec les entêtes (#include) nécessaires. * inclure un code minimal. Pour augmenter le nombre de lecteurs potentiels susceptibles de lire et tester votre programme, il est certainement avisé de ne pas envoyer un programme source de 4Go. * poster une seule unité de traduction : fusionner fred.H et fred.C si nécessaire. * signaler les utilitaires utilisés : compilateur, version, système d'exploitation, ... * poster les diagnostics exacts : bien distinguer les messages du compilateur, chargeur et ceux reçus lors de l'exécution. 1.1.8. On m'a offert (pour mes 15 ans) un logiciel révolutionnaire programmé en C++. Mais je ne sais pas l'utiliser. Le forum fr.comp.lang.c++ n'est-il pas un bon endroit poser mes questions ? Poster dans fr.comp.lang.c++ uniquement si la question concerne le langage C++ lui-même. Les questions relatives aux systèmes d'exploitation doivent être dirigées vers les groupes spécifiques. 1.1.9. Où puis-je trouver la version française de la « C++ FAQ Lite » ? La version française de « C++ FAQ Lite » est disponible en ligne ici : http://www.ifrance.com/jlecomte/c++/c++-faq-lite/. [ blah ] _________________________________________________________________ 1.2. C++ sur le Réseau 1.2.1 Ou est ce que je trouve un compilateur C++ gratuit ? * GCC : http://gcc.gnu.org/ * DJGPP : http://www.delorie.com/djgpp/ * Borland C++ 5.5 : http://www.inprise.fr/download/compilateurs/ _________________________________________________________________ 1.3. Qu'est-ce que c'est C++ ? C++ n'est pas une religion, ni un parti politique ; c'est un langage de programmation. 1.3.1. C++ est-il un langage orienté objet ? La réponse la plus simple est non. La réponse la plus verbeuse est que C++ n'est pas un langage orienté objet mais qu'il supporte la programmation orientée objet. En réalité, C++ est un langage « multi-paradigme », c'est-à-dire qu'il supporte plusieurs approches de la programmation : * programmation procédurale, * programmation fonctionnelle, * programmation orientée objet, * programmation générique, * programmation par objet. 1.3.2 Je veux apprendre C++, dois-je d'abord commencer par le C ? La réponse la plus simple est non. Apprendre le langage C dans l'espoir de maîtriser le langage C++ peut même constituer un handicap. Il est plus bénéfique pour une personne n'ayant pas eu de contact avec le langage C de passer directement au C++. 1.3.3 Y a-t-il des classiques de C++ ? Oui, il existe une vaste littérature sur C++. Voici une liste très courte de livres qu'on peut conseiller : -- The C++ Programming Language, 3rd edition Bjarne Stroustrup (2000 Addison-Wesley) Special Edition -- C++ Primer, 3rd edition Stanley B. Lippman et Josée Lajoie (1998, Addison-Wesley) -- Essential C++ Stanley B. Lippman (200, Addison-Wesley) -- Accelerated C++ Andrew R. Koenig et Barbara Moo (2000, Addison-Wesley) -- The Design and Evolution of C++ Bjarne Stroustrup, (Addison-Wesley) -- Exceptional C++ Herb Sutter (2000, Addison-Wesley) -- Effective C++ 2nd edition Scott Meyers (1997, Addison-Wesley) -- More Effective C++ Scott Meyers (1996, Addison-Wesley) -- Ruminations on C++ Andrew Koenig and Barabara Moo (1997, Addison Wesley) -- Inside the C++ Object Model Stanley B. Lippman, (1996, Addison Wesley) _________________________________________________________________ -o-o-o-o-o-o-o-o-o-o-o-o-o- _________________________________________________________________ 3. Les objets _________________________________________________________________ 3.1. Qu'est ce qu'un objet ? Formellement, un objet est une région de mémoire avec des propriétés définies au moment de sa création. Ces propriétés sont : * un nom (éventuel) * une durée de vie * un type _________________________________________________________________ 3.2. Qu'est-ce qu'un type ? Un type est ensemble de valeurs (dites valeurs du type) et une collection d'opérations sur ces valeurs. Il existe deux sortes de types en C++ : * les types primitifs ou types de base au nombre de quinze + void pour signaler l'absence de valeur ; + bool pour les expressions booléennes ; + char, signed char, unsigned char, + wchar_t pour manipuler du texte ; + short, unsigned short pour faire de l'arithmétique, mais ce n'est pas le type naturel de C++ ; + int, unsigned int le type entier de choix de C++ ; + long, unsigned long type entier potentiellement ayant une plus grande précision que les int + float pour les types flottants simple précision ; + double type flottant double précision ; + et long double type flottant avec précision étendue. La notion de précision varie d'un compilateur à l'autre. * et les types composés + les tableaux (à la C) d'objets, + les énumérations, + les pointeurs, + les types-classes, + les fonctions, Il est à noter que les types long long et unsigned long long ne font pas partie de C++ ni de C90. Ce sont des inventions de C99. _________________________________________________________________ -o-o-o-o-o-o-o-o-o-o-o-o-o- _________________________________________________________________ 7. Les déclarations _________________________________________________________________ 7.1 Qu'est-ce que la décoration des noms (name mangling) ? La décoration des noms est une technique inventée pour assurer une liaison « type-safe » de différentes unités de traduction, avec des lieurs utilisant des technologies relativement de bas niveau (tels que les lieurs C traditionnels par exemple). En effet, C++ permet de donner un même nom à différentes entités dans un même programme. Le mécanisme de surcharge des fonctions ou des opérateurs repose essentiellement sur cette possibilité ; on peut également avoir une variable globale dans un namespace, des fonctions ayant des paramètres différents dans un autre référentiel lexical (namespace), différentes instanciations d'une même fonction template dans un troisième, ... Dans le schéma classique de compilation séparée, le traducteur ne voit souvent qu'une portion d'un programme alors que le lieur en voit la totalité. Avec la plupart des lieurs traditionnels disponibles sur la majorité des plate-formes, les formats utilisés pour représenter un programme C++ en code objet ne permettent généralement pas au traducteur de spécifier au lieur les informations de type. Pour garantir une liaison « type-safe » des différentes unités de traduction, les traducteurs n'utilisent pas directement le nom donné par le programmeur mais ils l'augmentent de tout ce qui est significatif (cela peut être la signature s'il s'agit d'une fonction). Ce processus est appelé « décoration des noms » (« name mangling » en anglais). Par exemple voici trois fonctions avec le nom utilisé par un compilateur: void mangled(); // mangled__Fv namespace FAQ { void mangled(); // mangled__3FAQv int mangled(int); // mangled__3FAQi } Deux traducteurs différents utiliseront (en général) des schémas de décoration différents. _________________________________________________________________ 7.2. Mais alors, n'est-il généralement pas impossible de lier deux unités de traduction traduites par des compilateurs différents? La norme n'aurait-elle pas dû imposer une décoration commune ? On accuse souvent la décoration des noms d'être la cause pour laquelle il est impossible de lier ensemble des objets compilés par des compilateurs différents. En réalité, c'est confondre une solution à un problème avec sa cause : la décoration des noms empêche la liaison entre deux unités de traduction produites par des traducteurs différents car ces derniers n'implémentent pas forcément le langage de la même façon : la manière dont les exceptions sont levées, la manière dont les fonctions virtuelles sont appelées, comment est passé this, quels alignements respecter pour les différents champs. Ces détails d'implémentation empêcheraient généralement la bonne exécution même si l'édition de lien était possible. Pour s'assurer que les problèmes seront découverts à temps, les traducteurs utilisent volontairement des schémas de décoration de noms différents. Le propos de la norme du langage C++ n'est pas de dicter la structure interne d'un traducteur de programme particulier, mais de codifier l'interprétation des programmes C++. L'ensemble des contraintes à respecter pour permettre de lier du code compilé par des compilateurs différents fait partie de ce qu'on appelle une ABI (Application Binary Interface). Il est évident que l'ABI dépend du langage et du processeur. Il l'est peut-être un peu moins que l'ABI peut dépendre également de l'OS (certains OS ont une notion d'exception, il est assez naturel de vouloir une certaine correspondance entre les exceptions de l'OS et celles du language) et de la version particulière d'un compilateur. Maintenant que la norme est figée, on peut espérer que les fabricants de traducteurs de programmes C++ s'entendent sur une ABI commune, comme cela est déjà le cas pour le C (mais les problèmes ne sont pas aussi compliqués pour le C). Il y a une tentative de définition d'ABI pour le C++ pour l'IA64 : http://reality.sgi.com/dehnert_engr/cxx/abi.html. _________________________________________________________________ -o-o-o-o-o-o-o-o-o-o-o-o-o- _________________________________________________________________ 9. Les classes _________________________________________________________________ 9.1. Qu'est-ce qu'une classe ? Une classe est un outil d'abstraction. Une classe introduit un type d'objet unique dans un programme C++. Elle définit également une portée (appelée portée de classe). Cette dernière propriété est à la base de la technique des classes de traits. _________________________________________________________________ 9.2. Quelle est la différence entre une classe et une structure ? Conceptuellement il n'y a pas de différence. Un programmeur C peut voir une classe comme une structure dont les champs et fonctions membres sont privés par défaut. Mais cette vision est sûrement peu communicative. _________________________________________________________________ 9.3 Mais qu'est-ce donc une classe de traits ? Il est difficile de donner une définition précise d'une classe de traits, mais en première approximation on peut dire que c'est une classe qui ne possède pas de membres non-statiques. Un exemple typique est la classe template std::numeric_limits<>. _________________________________________________________________ -o-o-o-o-o-o-o-o-o-o-o-o-o- _________________________________________________________________ 21. Chaînes de caractères _________________________________________________________________ 21.1. Comment définir une variable de type « chaîne de caractères » ? Définir une variable de type chaîne de caractères est tout aussi simple que définir une variable de type entier. Il suffit de savoir que « chaîne de caractères » se prononce std::string en C++. Cette classe standard, définie par l'entête standard , comprend les opérations classiques (affectation, comparaison, concaténation, envoi vers un flux...). 21.2. Mais alors, qu'est-ce donc que ce char* que je vois toujours ? C'est un vestige de C. L'introduction de std::string dans le langage est relativement récente. Auparavant, pour manipuler une chaîne de caractères, il fallait utiliser un tableau de caractères, avec en fin du tableau un caractère sentinelle : le caractère nul '\0'. On manipulait généralement ce tableau par l'intermédiaire de pointeurs, et toute une série de fonctions qui sont responsables d'effectuer les opérations de base sur cette structure (strcat(), strcpy(), strcmp(),...). Ces fonctions existent toujours, mais leur usage est déconseillé. 21.3. Pourquoi vaut-il mieux utiliser std::string que char* ? Le point important est que pour manipuler (correctement) les char* il faut prêter une attention particulière au problème de gestion de la mémoire -- il faut que celui qui alloue de la mémoire et celui qui retourne la mémoire respectent strictement une politique bien établie. Outre que ça laisse la porte ouverte à beaucoup d'erreurs, cette approche rend difficile l'écriture d'un programme correct comportant des exceptions (la seule solution passe par l'écriture d'une classe du type std::string). 21.4. Hmmm, je vois. Mais certains composantes de la bibliothèque standard prennent des const char* et pas des std::string. Comment faire ? Il existe en effet des fonctions standard prenant des const char* au lieu de std::string. Dans ce cas, std::string::c_str() permet de réaliser la conversion. Il faut noter que le pointeur retourné ne doit servir en aucune manière à modifier les données pointées. 21.5. Mais, n'est-ce pas plus lent ? Peut-être. Ne perdez pas de vue qu'un programme rapide et incorrect est d'une utilité presque nulle. Une classe comme std::string est typiquement le genre de classe qui est plutôt optimisée pas les fabricants de compilateurs. Si vous constatez que votre classe std::string est d'une lenteur inacceptable, parlez-en à votre fournisseur -- bien sûr en admettant qu'il vous écoute, mais il devrait pas en être autrement : vous êtes son client. _________________________________________________________________ -o-o-o-o-o-o-o-o-o-o-o-o-o- _________________________________________________________________ 27. Les flux d'entrée/sortie _________________________________________________________________ 27.1. Voilà, j'ai écrit une classe Toto vite fait bien fait avec une fonction opérateur operator<<(std::ostream&, const Toto&) pour afficher des Toto sur la sortie standard. Mais en fait, je voudrais également avoir ce qui apparaîtrait normalement sur la sortie standard sous forme de chaînes de caractères dans mon programme. Y a-t-il une formule magique à prononcer ? Non, vous n'avez ni à allumer sept bougies, ni à sacriifier un mouton. Il vous suffit d'utiliser les flux de sortie en mémoire implémentés par la classe std::ostringstream comme dans l'exemple ci-dessous : #include #include std::string toto_en_string(const Toto& toto) { std::ostringstream flux_en_memoire; flux_en_memoire << toto; return flux_en_memoire.str(); } 27.2. Fort bien. Mais comment je fais l'opération inverse, c'est-à-dire comment je transforme une chaîne de caractères en Toto ? Il n'y a rien de compliqué å faire. Il vous suffit de disposer d'une fonction opérateur operator>>(std::istream&, Toto&) et d'implorer la classe std::istringstream : #include #include void string_en_toto(const std::string& chaine, Toto& toto) { std::istringstream flux_en_memoire(chaine); flux_en_memoire >> toto; } _________________________________________________________________ La FAQ de fr.comp.lang.c++ Dernière modification : Mai 2001 Copyright (C) 1998-2001 Gabriel Dos Reis URL : http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/