2010-07-20 8 views
1

Les membres statiques me confondent parfois. Je comprends comment initialiser simple type construit tel que int avec quelque chose le long des lignes de int myClass::statVar = 10;, que vous placez dans un fichier .cpp, mais j'ai quelque chose du genre suivant:Initialisation des membres statiques de l'objet

class myClass 
{ 
public: 
// Some methods... 

protected: 
static RandomGenerator itsGenerator; 
} 

L'idée de base est Assez simple: myClass a besoin d'accéder à un générateur aléatoire pour l'une de ses fonctions membres. Je peux aussi avoir seulement quelques instances du générateur puisque chaque objet est assez grand. Cependant, le type RandomGenerator doit être "initialisé", pour ainsi dire, par un appel à RandomGenerator::Randomize(), ce que le compilateur ne vous permettra pas de faire puisqu'il ne s'agit pas d'une valeur constante (n'est-ce pas?).

Alors, comment puis-je faire ce travail?

Ou peut-être ne devrais-je pas utiliser une variable statique dans ce cas, et le faire d'une autre manière?

Répondre

2

Vous pouvez créer une classe wrapper qui hébergera RandomGenerator instance et appellera RandomGenerator::Randomize dans son constructeur. Mettez-le dans un champ privé, exposer un accesseur statique.

+0

Il est mauvais. La classe externe ne devrait pas connaître l'existence du générateur. Vous avez changé le chemin pour cela seulement. C'est une solution de contournement, mais ce n'est pas une solution. – Gangnus

+0

@Gangnus: Pas nécessairement. L'encapsulation est très bien, mais il n'y a rien de mal à fournir des politiques de l'extérieur, surtout si vous risquez de perdre plus qu'une seule responsabilité dans votre classe externe existante. –

2

Dans l'accesseur, si le membre n'est pas encore initialisé, initialisez-le.

+0

Je mise sur cette méthode. Je pense que c'est peut-être la meilleure solution, même si l'emballage du générateur semble aussi une idée élégante. –

+0

C'est MAUVAIS. La classe externe ne devrait pas connaître l'existence du générateur. Vous avez changé le chemin pour cela seulement. C'est une solution de contournement, mais ce n'est pas une solution. – Gangnus

1

Dans des cas comme ceux-ci, les singletons sont en réalité vos amis, malgré leurs autres inconvénients.

+0

Oui. J'ai peur, en C++ c'est le seul moyen vraiment correct. Tout réglage d'un champ privé profondément intérieur de l'espace extérieur est incorrectement incorrect. L'espace des Outers ne devrait pas connaître le générateur interne et son initialisation. – Gangnus

+0

@Gangus: Voir mes autres commentaires. Ce n'est pas nécessairement vrai. Parfois, c'est bien de fournir une politique de l'extérieur. Voir la bibliothèque standard - vous pouvez fournir des types d'allocation en tant que paramètres de modèle pour tous les types de conteneurs, et c'est tout à fait correct. –

0

Est-ce seulement une fonction qui nécessite RandomGenerator? Vous pouvez le faire de cette façon:

int myClass :: foo() { statique generateurAleatoire itsGenerator = generateurAleatoire :: Randomize() ... }

+0

Cela ne fonctionnerait pas car Randomize ne renvoie pas de générateur. Séparer les lignes entraînerait la randomisation du générateur chaque fois que vous entrez dans le bloc. –

1

Si RandomGenerator est copiable, vous pouvez utiliser une fonction d'assistance pour l'initialisation:

RandomGenerator init_rg() { 
    RandomGenerator rg; 
    rg.Randomize(); 
    return rg; 
} 

RandomGenerator myClass::itsGenerator = init_rg(); 
+0

soyez prudent lors de l'initialisation des variables globales (statiques) car la commande n'est pas garantie. – doron

1

Il suffit d'écrire une fonction qui renvoie une référence à un generateurAleatoire correctement randomisé et tourner itsGenerator en référence à un générateur:

class myClass 
{ 
public: 
// Some methods... 

protected: 
// make this a reference to the real generator 
static RandomGenerator& itsGenerator; 
public: 
static RandomGenerator& make_a_generator() 
{ 
    RandomGenerator *g=0; 
    g=new RandomGenerator(); 
    g->Randomize(); 
    return *g; 
} 
} 

RandomGenerator& myClass::itsGenerator=myClass::make_a_generator(); 
+0

Pourquoi est-ce si compliqué si vous pouvez simplement renvoyer une instance allouée par pile et laisser NRVO s'occuper du reste ou utiliser une instance 'static' locale de fonction? –

+0

RandomGenerator a besoin d'un constructeur de copie accessible même avec NRVO. Je voulais juste éviter les exigences inutiles. –

0

Si seulement myClass a besoin de la RandomGenerator, puis:

myClass::myClass() 
{ 
    itsGenerator.Randomize(); 
} 

t-il si vous êtes-randomisez votre générateur aléatoire pour chaque objet? Je suppose que non ;-)

Questions connexes