68 votes

Comment déclarer un const char* statique dans votre fichier d'en-tête ?

J'aimerais définir une constante char* dans mon fichier d'en-tête pour que mon fichier .cpp l'utilise. J'ai donc essayé ceci :

private:
    static const char *SOMETHING = "sommething";

Ce qui m'amène à l'erreur de compilation suivante :

erreur C2864 : 'SomeClass::SOMETHING' : seules les données intégrales statiques constantes peuvent être initialisés dans une classe

Je suis nouveau dans le domaine du C++. Qu'est-ce qui se passe ici ? Pourquoi est-ce illégal ? Et comment faire autrement ?

75voto

Keats Points 8938

Vous devez définir les variables statiques dans une unité de traduction, sauf si elles sont de type intégral.

Dans votre en-tête :

private:
    static const char *SOMETHING;
    static const int MyInt = 8; // would be ok

Dans le fichier .cpp :

const char *YourClass::SOMETHING = "something";

Norme C++, 9.4.2/4 :

Si un membre de données statiques est de type const intégrale ou de type énumération const, sa déclaration dans la classe peut spécifier un constant-initializer qui doit être une expression constante intégrale. Dans ce cas, le membre peut apparaître dans expressions constantes intégrales dans sa portée. Le membre doit toujours être défini dans la portée d'un espace de nom s'il est utilisé dans le programme et que l'espace de nom ne doit pas contenir d'initialisateur initialisateur.

30voto

AndreyT Points 139512

Pour répondre à la question de l'OP sur la raison pour laquelle cela n'est autorisé qu'avec les types intégraux.

Lorsqu'un objet est utilisé comme une lvalue (c'est-à-dire comme quelque chose qui a une adresse en mémoire), il doit satisfaire à la "règle de la définition unique" (ODR), c'est-à-dire qu'il doit être défini dans une et une seule unité de traduction. Le compilateur ne peut pas et ne décidera pas dans quelle unité de traduction définir cet objet. C'est votre responsabilité. Par définir cet objet quelque part, vous ne faites pas que le définir, vous dites en fait au compilateur que vous voulez le définir ici en ce unité de traduction spécifique.

En revanche, dans le langage C++, les constantes intégrales ont un statut spécial. Elles peuvent former des expressions constantes intégrales (ICE). Dans les ICEs les constantes intégrales sont utilisées comme des constantes ordinaires valeurs pas comme objets (c'est-à-dire qu'il n'est pas pertinent de savoir si cette valeur intégrale a une adresse dans le stockage ou non). En fait, les ICE sont évaluées au moment de la compilation. Afin de faciliter une telle utilisation des constantes intégrales, leurs valeurs doivent être visibles globalement. Et la constante elle-même n'a pas vraiment besoin d'une place réelle dans le stockage. Pour cette raison, les constantes intégrales ont reçu un traitement spécial : il a été autorisé d'inclure leurs initialisateurs dans le fichier d'en-tête, et l'obligation de fournir une définition a été assouplie (d'abord de facto, puis de jure).

Les autres types de constantes n'ont pas de telles propriétés. Les autres types de constantes sont pratiquement toujours utilisés comme valeurs l (ou du moins ne peuvent pas participer à des ICE ou à quoi que ce soit de similaire à l'ICE), ce qui signifie qu'ils nécessitent une définition. Le reste suit.

18voto

Steve Jessop Points 166970

L'erreur est que vous ne pouvez pas initialiser un static const char* au sein de la classe. Vous ne pouvez y initialiser que des variables entières.

Vous devez déclarer la variable membre dans la classe, puis l'initialiser en dehors de la classe :

// fichier d'en-tête

class Foo {
    static const char *SOMETHING;
    // rest of class
};

// fichier cpp

static const char *Foo::SOMETHING = "sommething";

Si cela vous semble gênant, dites-vous que c'est parce que l'initialisation ne peut apparaître que dans une seule unité de traduction. Si elle se trouvait dans la définition de la classe, elle serait généralement incluse dans plusieurs fichiers. Les entiers constants sont un cas particulier (ce qui signifie que le message d'erreur n'est peut-être pas aussi clair qu'il pourrait l'être), et les compilateurs peuvent effectivement remplacer les utilisations de la variable par la valeur entière.

En revanche, un char* La variable pointe vers un objet réel en mémoire, qui est nécessaire pour exister réellement, et c'est la définition (y compris l'initialisation) qui fait exister l'objet. La "règle de la définition unique" signifie que vous ne voulez donc pas la placer dans un en-tête, car toutes les unités de traduction incluant cet en-tête contiendraient alors la définition. Ils ne pourraient pas être liés ensemble, même si la chaîne de caractères contient les mêmes caractères dans les deux cas, car selon les règles actuelles du C++, vous avez défini deux objets différents avec le même nom, et ce n'est pas légal. Le fait qu'ils contiennent les mêmes caractères ne rend pas la chose légale.

9voto

pgast Points 1240
class A{
public:
   static const char* SOMETHING() { return "something"; }
};

Je le fais tout le temps - surtout pour les paramètres par défaut des constantes coûteuses.

class A{
   static
   const expensive_to_construct&
   default_expensive_to_construct(){
      static const expensive_to_construct xp2c(whatever is needed);
      return xp2c;
   }
};

3voto

asveikau Points 16871

Si vous utilisez Visual C++, vous pouvez le faire de manière non portative en utilisant des indications à l'éditeur de liens...

// In foo.h...

class Foo
{
public:
   static const char *Bar;
};

// Still in foo.h; doesn't need to be in a .cpp file...

__declspec(selectany)
const char *Foo::Bar = "Blah";

__declspec(selectany) signifie que même si Foo::Bar sera déclaré dans plusieurs fichiers d'objets, l'éditeur de liens n'en retiendra qu'un seul.

Gardez à l'esprit que cela ne fonctionnera qu'avec la chaîne d'outils Microsoft. Ne vous attendez pas à ce qu'il soit portable.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X