web-dev-qa-db-fra.com

Initialiser les variables statiques dans la classe C ++?

J'ai remarqué que certaines de mes fonctions dans une classe n'accèdent pas à l'objet. Je les ai donc faites static. Ensuite, le compilateur m'a dit que toutes les variables auxquelles ils ont accès doivent également être statiques - eh bien, tout à fait compréhensibles jusqu'à présent. J'ai un tas de variables de chaîne telles que

string RE_ANY = "([^\\n]*)";
string RE_ANY_RELUCTANT = "([^\\n]*?)";

et ainsi de suite en classe. Je les ai ensuite toutes faites static const parce qu'ils ne changent jamais. Cependant, mon programme ne compile que si je les déplace hors de la classe: sinon, MSVC++ 2010 se plaint "Seules des variables intégrales à constante statique statique peuvent être initialisées dans une classe".

Eh bien c'est dommage. Y at-il un travail autour? Je voudrais les laisser dans la classe à laquelle ils appartiennent.

67
Felix Dombek

Ils ne peuvent pas être initialisés à l'intérieur de la classe, mais ils peuvent l'être à l'extérieur de la classe, dans un fichier source:

// inside the class
class Thing {
    static string RE_ANY;
    static string RE_ANY_RELUCTANT;
};

// in the source file
string Thing::RE_ANY = "([^\\n]*)";
string Thing::RE_ANY_RELUCTANT = "([^\\n]*?)";

Mise à jour

Je viens de remarquer la première ligne de votre question - vous ne voulez pas rendre ces fonctions static, vous voulez créer eux const. Les rendre static signifie qu'ils ne sont plus associés à un objet (ils ne peuvent donc accéder à aucun membre non statique), et rendre les données statiques signifie qu'ils seront partagés avec tous les objets de ce type. Ce n'est peut-être pas ce que vous voulez. Les rendre const signifie simplement qu'ils ne peuvent modifier aucun membre, mais qu'ils peuvent toujours y accéder.

115
Mike Seymour

Mike Seymour vous a donné la bonne réponse, mais pour ajouter ...
C++ vous permet de déclarer et de définir dans votre corps de classe uniquement types intégraux de constante statique, comme le compilateur le dit. Donc, vous pouvez réellement faire:

class Foo
{
    static const int someInt = 1;
    static const short someShort = 2;
    // etc.
};

Et vous ne pouvez le faire avec aucun autre type. Dans ce cas, vous devez les définir dans votre fichier .cpp.

28
Santiago V.

Depuis C++ 11, cela peut être fait dans une classe avec constexpr.

class stat {
    public:
        // init inside class
        static constexpr double inlineStaticVar = 22;
};

La variable est maintenant accessible avec:

stat::inlineStaticVar
15
0ax1

Les variables membres statiques doivent être déclarées dans la classe puis définies en dehors de celle-ci!

Il n'y a pas de solution de contournement, il suffit de mettre leur définition réelle dans un fichier source.


D'après votre description, vous sentez que vous n'utilisez pas les variables statiques correctement. Si elles ne changent jamais, vous devriez utiliser variable constante, mais votre description est trop générique pour en dire plus.

Les variables membres statiques ont toujours la même valeur pour toutes les instances de votre classe: si vous modifiez une variable statique d'un objet, elle le sera également pour tous les autres objets (et vous pourrez également y accéder sans une instance de la classe - c'est à dire: un objet).

15
peoro

Je pense qu'il est intéressant d'ajouter qu'une variable statique n'est pas la même chose qu'une variable constante.

en utilisant une variable constante dans une classe

struct Foo{
    const int a;
    Foo(int b) : a(b){}
}

et nous le déclarerions comme si

fooA = new Foo(5);
fooB = new Foo(10);
// fooA.a = 5;
// fooB.a = 10;

Pour une variable statique

struct Bar{
    static int a;
    Foo(int b){
        a = b;
    }
}
Bar::a = 0; // set value for a

qui est utilisé comme si

barA = new Bar(5);
barB = new Bar(10);
// barA.a = 10;
// barB.a = 10;
// Bar::a = 10;

Vous voyez ce qui se passe ici. La variable constante, qui est instanciée avec chaque instance de Foo, lorsque Foo est instancié, a une valeur distincte pour chaque instance de Foo et elle ne peut pas être modifiée par Foo.

Où, comme avec Bar, ne représente qu'une valeur pour Bar :: a, quel que soit le nombre d'instances de Bar créées. Ils partagent tous cette valeur, vous pouvez également y accéder en tant qu’instances de Bar. La variable statique respecte également les règles pour public/private, vous pouvez donc faire en sorte que seules les instances de Bar puissent lire la valeur de Bar :: a;

9
thecoshman

Juste pour ajouter au-dessus des autres réponses. Pour initialiser un membre statique complexe, vous pouvez le faire comme suit:

Déclarez votre membre statique comme d'habitude.

// myClass.h
class myClass
{
static complexClass s_complex;
//...
};

Créez une petite fonction pour initialiser votre classe s’il n’est pas trivial de le faire. Ceci sera appelé la seule fois où le membre statique est initialisé. (Notez que le constructeur de copie de complexClass sera utilisé, il devrait donc être bien défini).

//class.cpp    
#include myClass.h
complexClass initFunction()
{
    complexClass c;
    c.add(...);
    c.compute(...);
    c.sort(...);
    // Etc.
    return c;
}

complexClass myClass::s_complex = initFunction();
7
Sergio Basurco

Si votre objectif est d’initialiser la variable statique dans votre fichier d’en-tête (au lieu d’un fichier * .cpp, que vous voudrez peut-être si vous vous en tenez à un idiome "en-tête uniquement"), vous pouvez contourner le problème d’initialisation en utilisant un modèle. Les variables statiques basées sur des modèles peuvent être initialisées dans un en-tête sans que plusieurs symboles ne soient définis.

Voir ici pour un exemple:

Initialisation d'un membre statique dans un modèle de classe

2
Mark Lakata

Déplacez éventuellement toutes vos constantes dans un fichier .cpp sans déclaration dans le fichier .h. Utilisez des espaces de noms anonymes pour les rendre invisibles au-delà du module cpp.

// MyClass.cpp

#include "MyClass.h"

// anonymous namespace
namespace
{
    string RE_ANY = "([^\\n]*)";
    string RE_ANY_RELUCTANT = "([^\\n]*?)";
}

// member function (static or not)
bool MyClass::foo()
{
    // logic that uses constants
    return RE_ANY_RELUCTANT.size() > 0;
}
1
RuslanK

Certaines réponses semblent être trompeuses un peu.

Vous n'êtes pas obligé

  • Attribuez une valeur à l'objet statique lors de l'initialisation. L'affectation d'une valeur est facultatif.
  • Créer un autre .cpp fichier pour l’initialiser, cela peut être fait de la même manière dans le fichier Header.

#ifndef CLASS_A_H
#define CLASS_A_H
#include <string>
class A
{
private:
    static std::string str;
    static int x;
};
// Initialize with no values
std::string A::str;
int A::x;
// Initialize with values
//std::string A::str = "SO!";
//int A::x = 900;
#endif
1
X Stylish