Le code suivant était légal, mais il ne l'est plus, car la portée de i est limitée maintenant à l'intérieur de la boucle for:
for (int i = 0; i < 10; ++i) {
// ...
if
( /* quelque chose d'inquiétant */ )
break;
// ...
}
if (i != 10)
{
//
Nous sommes sortis de la boucle trop tôt; gérer ceci séparément
// ...
}
A moins que vous n'utilisiez une variable déclarée dans l'entête de la boucle for après le corps de la boucle for, la nouvelle règle de portée ne devrait pas rendre invalide votre code existant. Si vous utilisiez l'ancienne règle de portée, dans le plupart des cas le compilateur générera une erreur à la compilation par exemple "variable i n'est pas dans la portée".
Malheureusement il est possible que cette nouvelle règle change (silencieusement) la sémantique de votre code. Par exemple, si vous avez une variable globale i, le code ci-dessus if (i != 10) changera le sens du i de la boucle for avec l'ancienne règle vers le i de la variable globale avec la nouvelle règle. Ceci n'est pas bon. si vous êtes concerné par ce problème, vérifiez si votre compilateur n'a pas une option pour forcer l'utilisation de l'ancienne règle pour permettre une compilation correcte de votre vieux code.
Note: vous devriez éviter d'avoir le même nom de variable dans des portées imbriqués, tel qu'une variable globale i et une variable local i. En fait, vous devriez éviter d'utiliser des variables globales partout ou cela est possible. Si vous vous étiez conformé a cette règle de codage dans votre vieux code, vous n'auriez pas eu de problèmes avec cette nouvelle règle de portée des variables locales déclarées dans entête des boucles for.
Pourquoi ne puis je pas surcharger une fonction par son type de retour seulement?Vous devez utiliser la barre oblique ("/") plutôt que la barre oblique inverse ("\") pour vos #include de fichiers, même sur les systèmes d'exploitation qui utilisent la barre oblique tel que DOS, Windows, OS/2, etc. Par exemple:
#if 1
#include
"/version/next/alpha/beta/test.hpp" // BIEN!
#else
#include "\version\next\alpha\beta\test.hpp" // FAUX!
#endif
Notez que vous devriez utilisé la barre oblique ("/") pour tout vos noms de fichiers , et non pas seulement vos #include de fichiers.
N.D.T: certaines versions de compilateur/librairies C/C++ ont parfois des problèmes à utiliser "/" dans les noms de fichiers E.g Borland C++ 4.0, dans tout les cas si un(e) compilateur/librairie/fonction n'accepte pas le "/" c'est un bug de votre compilateur/librairie/fonction.
[ Haut | Bas | Rechercher ]
Le code suivant était légal, mais il ne l'est plus, car la portée de i est limitée maintenant à l'intérieur de la boucle for:
for (int i = 0; i < 10; ++i) {
// ...
if
( /* quelque chose d'inquiétant */ )
break;
// ...
}
if (i != 10)
{
//
Nous sommes sortis de la boucle trop tôt; gérer ceci séparément
// ...
}
A moins que vous n'utilisiez une variable déclarée dans l'entête de la boucle for après le corps de la boucle for, la nouvelle règle de portée ne devrait pas rendre invalide votre code existant. Si vous utilisiez l'ancienne règle de portée, dans le plupart des cas le compilateur générera une erreur à la compilation par exemple "variable i n'est pas dans la portée".
Malheureusement il est possible que cette nouvelle règle change (silencieusement) la sémantique de votre code. Par exemple, si vous avez une variable globale i, le code ci-dessus if (i != 10) changera le sens du i de la boucle for avec l'ancienne règle vers le i de la variable globale avec la nouvelle règle. Ceci n'est pas bon. si vous êtes concerné par ce problème, vérifiez si votre compilateur n'a pas une option pour forcer l'utilisation de l'ancienne règle pour permettre une compilation correcte de votre vieux code.
Note: vous devriez éviter d'avoir le même nom de variable dans des portées imbriqués, tel qu'une variable globale i et une variable local i. En fait, vous devriez éviter d'utiliser des variables globales partout ou cela est possible. Si vous vous étiez conformé a cette règle de codage dans votre vieux code, vous n'auriez pas eu de problèmes avec cette nouvelle règle de portée des variables locales déclarées dans entête des boucles for.
[ Haut | Bas | Rechercher ]
Le code suivant était légal, mais il ne l'est plus, car la portée de i est limitée maintenant à l'intérieur de la boucle for:
for (int i = 0; i < 10; ++i) {
// ...
if
( /* quelque chose d'inquiétant */ )
break;
// ...
}
if (i != 10)
{
//
Nous sommes sortis de la boucle trop tôt; gérer ceci séparément
// ...
}
A moins que vous n'utilisiez une variable déclarée dans l'entête de la boucle for après le corps de la boucle for, la nouvelle règle de portée ne devrait pas rendre invalide votre code existant. Si vous utilisiez l'ancienne règle de portée, dans le plupart des cas le compilateur générera une erreur à la compilation par exemple "variable i n'est pas dans la portée".
Malheureusement il est possible que cette nouvelle règle change (silencieusement) la sémantique de votre code. Par exemple, si vous avez une variable globale i, le code ci-dessus if (i != 10) changera le sens du i de la boucle for avec l'ancienne règle vers le i de la variable globale avec la nouvelle règle. Ceci n'est pas bon. si vous êtes concerné par ce problème, vérifiez si votre compilateur n'a pas une option pour forcer l'utilisation de l'ancienne règle pour permettre une compilation correcte de votre vieux code.
Note: vous devriez éviter d'avoir le même nom de variable dans des portées imbriqués, tel qu'une variable globale i et une variable local i. En fait, vous devriez éviter d'utiliser des variables globales partout ou cela est possible. Si vous vous étiez conformé a cette règle de codage dans votre vieux code, vous n'auriez pas eu de problèmes avec cette nouvelle règle de portée des variables locales déclarées dans entête des boucles for.
Pourquoi ne puis je pas surcharger une fonction par son type de retour seulement?[ Haut | Bas | Rechercher ]
Le problème avec les objets persistants est de sauvegarder sur un media le code de leur fonction membre (N.D.T : ?? FIXME effectively store their member function code) avec leurs données membres (et les données membres et code des fonctions membres des objets inclus, de leur classe de base, etc.). Ceci n'est pas trivial quand vous devez faire cela vous même. Le C++ ne fournit pas de support pour les objets persistants. les bases de données C++/Orienté Objet permettent d'aider à cacher les mécanismes utilisés pour implémenter les objets persistants.
[ Haut | Bas | Rechercher ]
#include <iostream.h>
int main()
{
float a = 1000.43;
float b = 1000.0;
cout << a - b << '\n';
}
(Sur une des implémentations du C++, ceci affiche 0.429993)
Démenti: La frustration éprouvé avec l'arrondi/la troncation/l'approximation n'est pas vraiment un problème venant du C++; c'est un problème de technique informatique. Toutefois, les gens continue a poser cette question sur fr.comp.lang.c++, aussi ceci est une réponse nominal.
Réponse: Les nombres en virgule flottantes sont des approximations. Le standard IEEE pour les nombres en virgules flottantes sur 32 bits supporte: 1 bit de signe, 8 bits d'exposant, et 23 bits de mantisse. Etant donné que les nombres en virgules flottantes sont normalisé sous la forme 1.xxxxx... le 1 en tète est sous-entendu et n'est pas codé ainsi on obtient 24 bits de mantisse. le nombre 1000.43 ne peut pas être représenté (et beaucoup d'autre nombres aussi) de façon exacte dans le format float ou double. 1000.43 est représenté par le le modèles de bits suivants (le "s" montre la position du bit de signe, les "e" montre les positions des bits d'exposants, et les "m" les positions des bits de mantisse):
seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm
01000100011110100001101110000101
La mantisse mise a l'échelle avec l'exposant est 1111101000.01101110000101 ou 1000 + 7045/16384. La partie fractionnaire est 0.429992675781. Avec une précision de 24 bits de mantisse vous obtenez une précision maximum de 1 / 16 millions. Le type double fournit une précision plus élevé (53 bits de mantisse).
[ Haut | Bas | Rechercher ]
Utiliser une déclaration anticipée.
Parfois vous pouvez avoir besoin de déclarer deux classes qui se références l'une l'autre. Ceci est appelé une dépendance circulaire. Par exemple:
class Fred {
public:
Barney* foo();
// Erreur: Symbole inconnu 'Barney'
};
class Barney {
public:
Fred* bar();
};
La classe Fred possède une fonction membre qui retourne un Barney*, et la classe Barney possède une fonction membre qui retourne un Fred*. Vous pouvez informer le compilateur de l'existence d'une classe ou d'un structure en utilisant une "déclaration anticipée":
class Barney;
Cette ligne doit apparaître avant la déclaration de la classe Fred. Elle informe simplement le compilateur que le nom Barney est une classes, et de plus c'est une promesse au compilateur que vous fournirez éventuellement une définition complète de cette class.
[ Haut | Bas | Rechercher ]
L'ordre des déclarations est critique.
Le compilateur générera une erreur si la première classe contient un objet (par opposition avec un pointeur vers un objet) du type de la seconde classe. Par exemple,
class Fred; // Ok: déclaration anticipé
class Barney {
Fred x; // Erreur: La déclaration de Fred
est incomplète
};
class Fred {
Barney* y;
};
Une solution pour résoudre ce problème est d'inverser l'ordre de déclaration des classes ainsi la classe "utilisée" sera définie avant la classe qui l'utilise:
class Barney; // Ok: déclaration anticipé
class Fred {
Barney* y; // Ok: un pointeur vers objet déclaré
};
class Barney {
Fred x; // Ok: un objet déjà définit
};
Notez qu'il n'est jamais légal pour chacune des classes de contenir un objet de l'autre classe car cela impliquerait que les objets aurait une taille infini. En d'autres mots, si une instance de Fred contient un Barney (par opposition avec un Barney*), et un Barney contient un Fred (par opposition avec un Fred*), le compilateur générera une erreur.
[ Haut | Bas | Rechercher ]
L'ordre de déclaration des classes est critique.
La compilateur générera une erreur si la première classe contient une fonction en ligne qui invoque une fonction membre de la seconde classe. Par exemple,
class Fred; // Ok: déclaration anticipée
class Barney {
public:
void
method()
{
x->yabbaDabbaDo();
// Erreur: Fred utilisé avant être définit
}
private:
Fred* x; // Ok: un pointeur vers un objet déclaré
};
class Fred {
public:
void yabbaDabbaDo();
private:
Barney* y;
};
Une solution pour résoudre ce problème est de déplacer la fonction fautive dans le fichier Barney.cpp en tant que fonction non-inline. Une autre solution est d'inverser l'autre de déclaration des classes ainsi la classe "utilisé" sera déclaré avant la classe l'utilisant.
class Barney; // Ok: déclaration anticipée
class Fred {
public:
void
yabbaDabbaDo();
private:
Barney* y;
// Ok: un pointeur vers un objet déclaré
};
class Barney
{
public:
void method()
{
x->yabbaDabbaDo(); // Ok: Fred est définit à
ce point
}
private:
Fred* x;
};
Rappelez vous ceci: quand vous utilisez une déclaration anticipée , vous pouvez simplement utiliser le symbole déclaré; vous ne pouvez rien faire qui requiert de la part du compilateur la connaissance de toute ou partie de la définition du symbole. Spécifiquement vous ne pouvez pas accéder aux membres de la classe déclarée. N.D.T: ni utilisé sizeof (symbole).
[ Haut | Bas | Rechercher ]
Car la classe template vector<> a besoin de connaître le sizeof() des éléments contenus, de plus le vector<> aura probablement besoin de l'accès à certains membres des objets contenus (tel que le constructeur par copie, le destructeur, etc.). Par exemple,
class Fred; // Ok: déclaration anticipée
class Barney {
vector<Fred> x; // Erreur: la déclaration de
Fred est incomplète
};
class Fred {
Barney* y;
};
Une solution est de modifier la classe Barney pour qu'elle utilise un vector<> de pointeur de Fred plutôt qu'un vector<> d'objets Fred:
class Fred; // Ok: déclaration anticipée
class Barney {
vector<Fred*> x; // Ok: Barney peut utilisé
des pointeurs de Fred
};
class Fred {
Barney* y;
};
Une autre solution est d'inverser l'ordre de déclaration des classes ainsi Fred est définit avant Barney:
class Barney; // Ok: déclaration anticipé
class Fred {
Barney* y; // Ok: un pointeur vers un objet déclaré
};
class Barney {
vector<Fred> x; // Ok: Fred est définit
à ce point
};
Rappelez vous ceci: quand vous utilisez une classe comme paramètre de template, la déclaration de cette classe doit être complète et pas être simplement une déclaration anticipée .
[ Haut | Bas | Rechercher ]
Ecrire à l'auteur,
au traducteur,
ou en savoir plus sur la traduction.
C++ FAQ Lite fr |
Table des matières |
Index |
A propos de l'auteur |
© |
Téléchargez votre propre copie ]
Dernière révision Sun Apr 13 23:54:26 PDT 2003