Comment déclarer une 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 moi .rpc fichier à utiliser. J'ai donc essayé ceci:

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

ce qui m'amène avec l'erreur de compilation suivante:

erreur C2864: "SomeClass:: SOMETHING" : uniquement données intégrales statiques de const les membres peuvent être initialisées dans un classe

je suis nouveau en C++. Ce qui se passe ici? Pourquoi est-ce illégal? Et comment pouvez-vous le faire sinon?

50
demandé sur Mark 2009-10-28 21:24:33

9 réponses

vous devez définir des variables statiques dans une unité de traduction, à moins qu'elles ne soient de types intégraux.

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";

C++ standard, 9.4.2/ 4:

si un élément de données statique est de const type d'énumération intégrale ou de const, sa déclaration dans la classe définition pouvez spécifier un constante d'initialiseur qui doit être une expression constante intégrale. Dans ce cas, le membre peut apparaître dans expressions constantes intégrales à l'intérieur son champ d'application. Le membre doit toujours être défini dans un namespace scope s'il est utilisées dans le programme et l'espace de noms la définition du champ d'application ne doit pas contenir initialiseur.

59
répondu KeatsPeeks 2014-07-25 07:32:28

pour répondre à la question de L'OP sur la raison pour laquelle il est seulement autorisé avec les types intégraux.

Lorsqu'un objet est utilisé comme valeur l (c.-à-d. comme quelque chose qui a une adresse en mémoire), il doit satisfaire à la "règle de définition unique" (RLL), I. e il doit être défini dans une seule unité de traduction. Le compilateur ne peut pas et ne veut pas décider dans quelle unité de traduction définir cet objet. C'est votre responsabilité. Par définissant cet objet quelque part vous n'êtes pas juste en le définissant, vous êtes effectivement dire au compilateur que vous souhaitez définir ici , dans ce spécifique de l'unité de traduction.

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

autres types constants n'ont pas de telles propriétés. D'autres types constants sont presque toujours utilisés comme valeurs L (ou du moins ne peuvent pas participer au CIEM ou à quelque chose de similaire à la glace), ce qui signifie qu'ils nécessitent une définition. Le reste suit.

26
répondu AnT 2009-10-28 20:18:28

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

vous devez déclarer la variable member 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

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

si cela semble ennuyeux, pensez-le comme étant parce que l'initialisation ne peut apparaître que dans un seul l'unité de traduction. Si c'était dans la définition de la classe, cela serait généralement inclus dans plusieurs fichiers. Les entiers constants sont un cas spécial (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.

au contraire, une variable char* pointe vers un objet réel en mémoire, qui est requis pour exister réellement, et c'est la définition (y compris l'initialisation) qui fait que le objet existe. La "règle d'une définition" signifie que vous ne voulez pas la mettre dans un en-tête, car alors toutes les unités de traduction incluant cet en-tête contiendraient la définition. Ils ne peuvent pas être reliés entre eux, même si la chaîne contient les mêmes caractères dans les deux, parce que sous les règles C++ actuelles vous avez défini deux objets différents avec le même nom, et ce n'est pas légal. Le fait qu'ils ont les mêmes caractères n'est pas légal.

16
répondu Steve Jessop 2016-02-24 00:26:52
class A{
public:
   static const char* SOMETHING() { return "something"; }
};

je le fais tout le temps - surtout pour les paramètres coûteux par défaut de const.

class A{
   static
   const expensive_to_construct&
   default_expensive_to_construct(){
      static const expensive_to_construct xp2c(whatever is needed);
      return xp2c;
   }
};
9
répondu pgast 2009-10-29 08:47:51

avec C++11 Vous pouvez utiliser le mot-clé constexpr et écrire dans votre en-tête:

private:
    static constexpr const char* SOMETHING = "something";



Notes:

  • constexpr rend SOMETHING un pointeur constant de sorte que vous ne pouvez pas écrire

    SOMETHING = "something different";
    

    plus tard.

  • définition dans le .fichier cpp:

    constexpr const char* MyClass::SOMETHING;
    
9
répondu Ignitor 2014-08-28 12:13:21

si vous utilisez Visual C++, vous pouvez le faire de manière non-portable en utilisant des indices pour le linker...

// 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, le linker n'en récupérera qu'un seul.

gardez à l'esprit que cela ne fonctionnera qu'avec la chaîne D'outils Microsoft. Ne vous attendez pas à être portables.

3
répondu asveikau 2009-10-28 18:33:33

il y a un truc que vous pouvez utiliser avec des modèles pour fournir des constantes h file only.

(note, Ceci est un exemple laid, mais fonctionne mot à mot au moins dans g++ 4.6.1.)

(les valeurs.php fichier)

#include <string>

template<int dummy>
class tValues
{
public:
   static const char* myValue;
};

template <int dummy> const char* tValues<dummy>::myValue = "This is a value";

typedef tValues<0> Values;

std::string otherCompUnit(); // test from other compilation unit

(principale.cpp)

#include <iostream>
#include "values.hpp"

int main()
{
   std::cout << "from main: " << Values::myValue << std::endl;
   std::cout << "from other: " << otherCompUnit() << std::endl;
}

(d'autres.cpp)

#include "values.hpp"

std::string otherCompUnit () {
   return std::string(Values::myValue);
}

de la Compilation (par exemple, g++ -o principal.rpc autres.rpc && ./ main) et voir deux unités de compilation se référant au même constante déclarée dans un en-tête:

from main: This is a value
from other: This is a value

dans MSVC, vous pouvez plutôt utiliser __declspec(selectany)

par exemple:

__declspec(selectany) const char* data = "My data";
3
répondu Torlack 2012-03-02 00:04:38

initialiseur Constant autorisé par la norme C++ Uniquement pour les types intégraux ou de dénombrement. Voir 9.4.2/4 pour plus de détails:

si un membre de données statiques est du type const integral ou const enumeration, sa déclaration dans la classe définition peut spécifier un initialiseur constant qui doit être une expression constante intégrale (5.19). Dans ce cas, le membre peut apparaître dans intégrale des expressions constantes. Le membre doit encore être défini dans un nom- espace scope s'il est utilisé dans le programme et la définition de scope namespace ne doit pas contenir d'initialiseur.

et 9.4.2 / 7:

Les éléments de données statiques

sont initialisés et détruits exactement comme les objets non locaux (3.6.2, 3.6.3).

alors vous devriez écrire quelque part dans le fichier cpp:

const char* SomeClass::SOMETHING = "sommething";
1
répondu Kirill V. Lyadvinsky 2009-10-28 18:36:22

pour répondre à la question pourquoi , les types intégraux sont spéciaux en ce qu'ils ne sont pas une référence à un objet alloué mais plutôt des valeurs qui sont dupliquées et copiées. C'est juste une décision d'implémentation prise lorsque le langage a été défini, qui était de gérer les valeurs en dehors du système objet et de manière aussi efficace et "inline" que possible.

cela n'explique pas exactement pourquoi ils sont autorisés comme initialisateurs dans un type, mais penser de celui-ci comme essentiellement un #define et puis il aura un sens en tant que partie du type et non partie de l'objet.

0
répondu DigitalRoss 2009-10-28 19:05:35