IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)



La fonction de ma classe entre en conflit avec une fonction standard, que faire ?
auteur : LFE
Définir dans une classe une fonction membre qui a le même nom qu'une fonction standard est possible, mais risque de poser problème lors de l'utilisation de cette fonction membre à l'intérieur de la classe. La fonction membre masque la fonction standard.
Il reste toutefois possible d'utiliser la fonction standard en faisant précéder son nom de ::.

class MaClasse { // .... int abs(int x); // masque la fonction standard abs // .... } int MaClasse::abs(int x) { return ::abs(x); // fait appel à la fonction standard abs() }

Puis-je utiliser des librairies écrites en C dans mes programmes C++ ?
auteur : LFE
oui, il est tout à fait possible d'utiliser des librairies écrites en C dans un programme C++ pour autant qu'elles soient déclarées correctement dans les fichiers d'en-tête en utilisant le extern "C" qui indique que la fonction doit être considérée comme du code C et non C++.

extern "C" { char* maFonctionC_1(); void maFunctionC2( char *param1); }

Pourquoi mes templates ne sont-ils pas reconnus à l'édition des liens ?
auteur : LFE
auteur : haypo
Contrairement aux classes 'normales', les templates ne peuvent pas avoir leur interface définie dans un fichier d'en-tête et leur implémentation dans un fichier .cpp.
Il faut absolument que le template soit entièrement défini dans le fichier d'en-tête (.h).

Une autre façon de faire permet de garder la logique du .h contenant l'interface et le .cpp contenant l'implémentation est la suivante :

// le .h #ifndef MON_TEMPLATE_H #define MON_TEMPLATE_H template <class T> class Liste { ... }; #include "mon_template.cpp" #endif // le .cpp #ifdef MON_TEMPLATE_H // évite les erreurs de compilation ;-) template <class T> Liste<T>::Liste () { ... } #endif

Est-il possible de capturer plusieurs exceptions dans un seul catch ?
auteur : LFE
Malheureusement, non, ce mécanisme n'est pas possible. Un catch ne pouvant capturer qu'un seul type d'exceptions, il faut définir autant de blocs try/catch qu'il y a d'exceptions possibles.

L'utilisation de

try { // ... } catch(...) { // ... }
permet de capturer toutes les exceptions pouvant survenir, mais il est, dans ce cas, impossible de faire la distinction.


Comment savoir si je dois dériver une classe ou l'encapsuler ?
auteur : LFE
J'applique une méthode simple : la question à se poser est la suivante : est-ce que X est un genre de Y, ou est-ce que X utilise un Y ?
Si la réponse est X est un genre de Y, il s'agit d'un cas où je dérive une classe.
Si la réponse est X utilise Y, il s'agit d'un cas où je vais encapsuler une classe.


Mon programme C++ compile parfaitement avec gcc 2.x, et marque pleins d'erreurs avec gcc 3.x
auteur : Anomaly
La raison la plus probable est l'absence de la directive using namespace std;. Cette directive était optionnelle avec gcc 2.x (ceci était un défaut de conformité au standard). Il faut maintenant, avec gcc 3.x qui est conforme au standard, la mettre dans chaque fichier source, après le bloc des #include. Le programme ainsi modifié compilera aussi bien avec gcc 2.x que gcc 3.x.


Pourquoi existet-il deux fichiers d'en-tête iostream et iostream.h et lequel utiliser ?
auteur : Anomaly
C'est parce que le standard C++ a évolué. Faire

#include <iostream.h>
est équivalent à faire

#include <iostream> using namespace std;
Le fichier iostream.h est présent par compatibilité avec les anciennes versions de C++ quand les namespaces n'existaient pas ; il ne faut plus l'utiliser dans les nouvelles applications.

De la même manière, pour la bibliothèque standard C, il est recommandé pour des raisons d'uniformisation d'inclure les noms de fichiers sans .h : ils sont préfixés par la lettre "c" (pour souligner le fait que ça vient du C). utilisez

#include <cstdlib>
plutôt que

#include <stdlib.h>

Qu'est-ce donc qu'une auto-affectation ?
auteur : Marshall Cline
Une auto-affectation a lieu quand quelqu'un affecte un objet à lui-même.

#include "Fred.hpp" // Déclaration de la classe Fred void userCode(Fred& x) { x = x; // Auto-affectation }
Bien évidemment, personne n'écrit du code pareil, mais parce que des pointeurs ou des références distinctes peuvent désigner le même objet (c'est l'aliasing), des auto-affectations peuvent avoir lieu derrière votre dos.

void userCode(Fred& x, Fred& y) { x = y; // C'est une auto-affectation si &x == &y } int main() { Fred z; userCode(z, z); return 0; }

Pourquoi l'auto-affectation peut-elle poser problème ?
auteur : Marshall Cline
Si vous ne prenez pas en compte le cas de l'auto-affectation, vous exposez les utilisateurs de vos classes à des bugs subtils qui peuvent avoir des conséquences désastreuses. Par exemple, l'affectation d'un objet de la classe ci-dessous à lui-même va poser un très gros problème.

class Wilma { }; class Fred { public: Fred() : p_(new Wilma()) { } Fred(const Fred& f) : p_(new Wilma(*f.p_)) { } ~Fred() { delete p_; } Fred& operator= (const Fred& f) { // Ce code n'est pas bon: il ne traite pas le cas de l'auto-affectation! delete p_; // Ligne 1 p_ = new Wilma(*f.p_); // Ligne 2 return *this; } private: Wilma* p_; };
Si quelqu'un assigne un objet de type Fred à lui-même, la ligne 1 va détruire à la fois this->p_ et f.p_ puisque *this et f désignent ici le même objet. Juste derrière, la ligne 2 utilise *f.p_, mais cet objet n'est plus valide puisqu'il a été détruit. Inutile de vous dire que cette utilisation risque fort de s'avérer catastrophique.

Retenez qu'il est votre responsabilité, en tant qu'auteur de la classe Fred, de garantir que l'affectation d'un objet de type Fred à lui-même ne pose pas de problèmes. Ne partez pas du principe que les utilisateurs de vos classes ne feront jamais ce genre d'affectation. Et ce sera de votre faute si un objet de votre classe fait crasher le programme dans le cas où on l'affecte à lui-même.

Notez aussi que dans l'exemple ci-dessus, l'opérateur Fred::operator= (const Fred&) contient un autre bug: Si une exception est lancée lors de l'évaluation de new Wilma(*f.p_) (par exemple., une exception plus-de-mémoire ou une exception lancée par le constructeur par copie de Wilma), this->p_ va se retrouver pointant sur de la mémoire qui n'est plus valide. La solution consiste à allouer les nouveaux objets avant de détruire les anciens.


Comment éviter les problèmes d'auto-affectation ?
auteur : Marshall Cline
Vous devez vous poser la question de l'auto-affectation à chaque fois que vous créez une classe. Mais ça ne veut pas dire qu'il est nécessaire que vous ajoutiez du code à toutes vos classes: ajouter du code n'est pas utile si vos objets peuvent être assignés à eux-mêmes sans que cela pose un problème.

Si vous devez modifier votre opérateur d'affectation, voici une technique simple et efficace :

Fred& Fred::operator= (const Fred& f) { if (this == &f) return *this; // Traite correctement le cas de l'auto-affectation // Ici se trouve le code normal de l'opérateur d'affectation... return *this; }
Ce test explicite n'est pas toujours nécessaire. Par exemple, si vous vouliez corriger l'opérateur d'affectation de la questionprécédente de façon à ce que les exceptions lancées par new et/ou les exceptions lancées par le par le constructeur de copie de la classe Wilma soient gérées correctement, vous écririez le code suivant. Et notez que ce code a pour (agréable) effet de bord de traiter correctement le cas de l'auto-affectation :

Fred& Fred::operator= (const Fred& f) { // Ce code traite correctement (même si c'est implicite) le cas de l'auto-affectation Wilma* tmp = new Wilma(*f.p_); // Pas de problème si une exception était levée ici delete p_; p_ = tmp; return *this; }
Dans un cas comme ci-dessus (où l'auto-affectation est sans danger mais inefficace), certains programmeurs veulent quand même ajouter "if (this == &f) return *this;" pour obtenir de meilleures performances dans le cas d'une auto-affectation. C'est la plupart du temps un mauvais choix, car si une auto-affectation a lieu une fois sur mille, alors le if consommera inutilement des cycles processeur dans 99,9% des cas.



Ce document issu de http://www.developpez.com est soumis à la licence GNU FDL traduit en français ici.
Permission vous est donnée de distribuer, modifier des copies de cette page tant que cette note apparaît clairement.
Certaines parties de ce document sont sous copyright Marshall Cline