187 votes

constructeurs statiques en C ++? besoin d'initialiser des objets statiques privés

Je veux avoir une classe avec un privé donnée membre statique (un vecteur qui contient tous les caractères a-z). En java ou en C#, je peux juste faire un "constructeur statique" qui sera exécuté avant de me faire toutes les instances de la classe, et met en place les données membres statiques de la classe. Il ne s'exécuter qu'une seule fois (comme les variables sont en lecture seule et ne doit être défini qu'une seule fois) et depuis c'est une fonction de la classe à laquelle il peut accéder à ses membres privés. Je pourrais ajouter du code dans le constructeur qui vérifie pour voir si le vecteur est initialisé, et l'initialiser si elle ne l'est pas, mais qui présente de nombreuses vérifications nécessaires et ne semble pas être la solution optimale pour le problème.

La pensée se présente à moi que depuis que les variables seront en lecture seule, il peut juste être public static const, afin que je puisse régler une fois à l'extérieur de la classe, mais une fois de plus, il semble un peu comme une moche hack.

Est-il possible d'avoir privé les données membres statiques dans une classe, si je ne veux pas les initialiser dans l'instance constructeur?

187voto

Daniel Earwicker Points 63298

Pour obtenir l'équivalent d'un constructeur statique, vous devez écrire une classe ordinaire distincte pour contenir les données statiques, puis créer une instance statique de cette classe ordinaire.

 class StaticStuff
{
     std::vector<char> letters_;

public:
     StaticStuff()
     {
         for (char c = 'a'; c <= 'z'; c++)
             letters_.push_back(c);
     }

     // provide some way to get at letters_
};

class Elsewhere
{
    static StaticStuff staticStuff; // constructor runs once, single instance

};
 

83voto

EFraim Points 7137

Bien vous pouvez avoir

 class MyClass
{
    public:
        static vector<char> a;

        static class _init
        {
          public:
            _init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
        } _initializer;
};
 

N'oubliez pas (dans le .cpp) ceci:

 vector<char> MyClass::a;
MyClass::_init MyClass::_initializer;
 

Le programme sera toujours lié sans la deuxième ligne, mais l'initialiseur ne sera pas exécuté.

21voto

Ant Points 3202

Dans le fichier .h:

 class MyClass {
private:
    static int myValue;
};
 

Dans le fichier .cpp:

 #include "myclass.h"

int MyClass::myValue = 0;
 

15voto

Douglas Mandell Points 71

Voici une autre approche semblable à celle de Daniel Earwicker, aussi, à l'aide de Konrad Rudolph, l'ami de classe de la suggestion. Ici, nous utilisons un intérieur privé, ami de la classe utilitaire pour initialiser les membres statiques de votre classe principale. Par exemple:

Fichier d'en-tête:

class ToBeInitialized
{
    // Inner friend utility class to initialize whatever you need

    class Initializer
    {
    public:
        Initializer();
    };

    friend class Initializer;

    // Static member variables of ToBeInitialized class

    static const int numberOfFloats;
    static float *theFloats;

    // Static instance of Initializer
    //   When this is created, its constructor initializes
    //   the ToBeInitialized class' static variables

    static Initializer initializer;
};

La mise en œuvre de fichier:

// Normal static scalar initializer
const int ToBeInitialized::numberOfFloats = 17;

// Constructor of Initializer class.
//    Here is where you can initialize any static members
//    of the enclosing ToBeInitialized class since this inner
//    class is a friend of it.

ToBeInitialized::Initializer::Initializer()
{
    ToBeInitialized::theFloats =
        (float *)malloc(ToBeInitialized::numberOfFloats * sizeof(float));

    for (int i = 0; i < ToBeInitialized::numberOfFloats; ++i)
        ToBeInitialized::theFloats[i] = calculateSomeFancyValue(i);
}

Cette approche a l'avantage de cacher complètement l'Initialiseur de classe du monde extérieur, en gardant tout ce qui est contenu dans la classe d'être initialisé.

9voto

Marc Mutz - mmutz Points 10367

Pas besoin d'un init() fonction std::vector peut être créé à partir d'une gamme:

// h file:
class MyClass {
    static std::vector<char> alphabet;
// ...
};

// cpp file:
#include <boost/range.hpp>
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
std::vector<char> MyClass::alphabet( boost::begin( ::alphabet ), boost::end( ::alphabet ) );

Notez, cependant, que la statique de type de classe causer des problèmes dans les bibliothèques, de sorte qu'ils devraient être évités.

C++11 Mise À Jour

Que de C++11, vous pouvez faire ceci à la place:

// cpp file:
std::vector<char> MyClass::alphabet = { 'a', 'b', 'c', ..., 'z' };

Il est sémantiquement équivalent à la C++98 solution dans l'original de la réplique, mais vous ne pouvez pas utiliser un littéral de chaîne sur le côté droit, il n'est donc pas complètement supérieur. Toutefois, si vous avez un vecteur de tout autre type de char, wchar_t, char16_t ou char32_t (tableaux de ce qui peut être écrit comme des littéraux de chaîne), le C++11 version strictement supprimer le code réutilisable sans introduire d'autres éléments de la syntaxe, par rapport au C++version 98.

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