Je veux avoir une classe avec un membre de données statique privé (un vecteur qui contient tous les caractères az). En java ou C #, je peux simplement créer un "constructeur statique" qui fonctionnera avant de créer des instances de la classe, et configure les données statiques membres de la classe. Il n'est exécuté qu'une seule fois (car les variables sont en lecture seule et ne doivent être définies qu'une seule fois) et comme il s'agit d'une fonction de la classe, il peut accéder à ses membres privés. Je pourrais ajouter du code dans le constructeur qui vérifie si le vecteur est initialisé, et l'initialiser si ce n'est pas le cas, mais cela introduit de nombreuses vérifications nécessaires et ne semble pas être la solution optimale au problème.
L'idée me vient à l'esprit que puisque les variables seront en lecture seule, elles peuvent simplement être des const statiques publiques, donc je peux les définir une fois en dehors de la classe, mais encore une fois, cela ressemble à un horrible hack.
Est-il possible d'avoir des membres de données statiques privés dans une classe si je ne veux pas les initialiser dans le constructeur d'instance?
la source
Réponses:
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.
la source
friend
cela a beaucoup de sens pour que la classeElsewhere
puisse facilement accéderStaticStuff
aux composants internes de (sans interrompre l'encapsulation de manière dangereuse, pourrais-je ajouter).Eh bien, vous pouvez avoir
N'oubliez pas (dans le .cpp) ceci:
Le programme sera toujours lié sans la deuxième ligne, mais l'initialiseur ne sera pas exécuté.
la source
MyClass::a.push_back(i)
place dea.push_back(i)
?_initializer
est un sous-objet deMyClass
. Les sous-objets sont initialisés dans cet ordre: sous-objets de classe de base virtuelle, dans l'ordre de la profondeur d'abord, de gauche à droite (mais en initialisant chaque sous-objet distinct une seule fois); puis des sous-objets de classe de base simples, dans l'ordre de la profondeur d'abord, de gauche à droite; puis les sous-objets membres dans l'ordre de déclaration. Il est donc sûr d'utiliser la stratégie d'EFraim, à condition que le code_initialiser
ne fasse référence qu'aux membres déclarés avant lui.Solution C ++ 11
Depuis C ++ 11, vous pouvez simplement utiliser des expressions lambda pour initialiser les membres de classe statiques. Cela fonctionne même si vous devez imposer un ordre de construction entre les différents membres statiques, ou si vous avez des membres statiques qui le sont
const
.En tête de fichier:
Fichier source:
la source
try catch
bloc si des exceptions peuvent être levées.Dans le fichier .h:
Dans le fichier .cpp:
la source
Voici une autre approche similaire à celle de Daniel Earwicker, utilisant également la suggestion de classe d'amis de Konrad Rudolph. Ici, nous utilisons une classe utilitaire d'ami privé interne pour initialiser les membres statiques de votre classe principale. Par exemple:
En tête de fichier:
Dossier d'implémentation:
Cette approche a l'avantage de masquer complètement la classe Initializer du monde extérieur, en conservant tout ce qui est contenu dans la classe à initialiser.
la source
ToBeInitialized::Initializer::Initializer()
est appelé, vous devez donc l'ajouterToBeInitialized::Initializer ToBeInitialized::initializer;
au fichier d'implémentation. J'ai pris certaines choses de votre idée et de l'idée d'EFraim, et cela fonctionne exactement comme j'en ai besoin et a l'air propre. Merci mec.Test::StaticTest()
est appelée exactement une fois lors de l'initialisation statique globale.L'appelant n'a qu'à ajouter une ligne à la fonction qui doit être son constructeur statique.
static_constructor<&Test::StaticTest>::c;
force l'initialisation dec
lors de l'initialisation statique globale.la source
Pas besoin de
init()
fonction,std::vector
peut être créée à partir d'une plage:Notez cependant que les statiques de type classe causent des problèmes dans les bibliothèques, elles doivent donc être évitées à cet endroit.
Mise à jour C ++ 11
À partir de C ++ 11, vous pouvez le faire à la place:
C'est sémantiquement équivalent à la solution C ++ 98 dans la réponse d'origine, mais vous ne pouvez pas utiliser une chaîne littérale sur le côté droit, donc ce n'est pas complètement supérieur. Toutefois, si vous avez un vecteur de tout autre type que
char
,wchar_t
,char16_t
ouchar32_t
(tableaux qui peuvent être écrits comme des chaînes), le C ++ version 11 sera strictement supprimer le code boilerplate sans introduire la syntaxe du langage, par rapport au C ++ 98 version.la source
Le concept de constructeurs statiques a été introduit en Java après avoir appris des problèmes en C ++. Nous n'avons donc pas d'équivalent direct.
La meilleure solution est d'utiliser des types POD qui peuvent être initialisés explicitement.
Ou faites de vos membres statiques un type spécifique qui a son propre constructeur qui l'initialisera correctement.
la source
En essayant de compiler et d' utiliser la classe
Elsewhere
(d' après la réponse d' Earwicker ), j'obtiens:Il ne semble pas possible d'initialiser des attributs statiques de types non entiers sans mettre du code en dehors de la définition de classe (CPP).
Pour faire cette compilation, vous pouvez utiliser " une méthode statique avec une variable locale statique à l'intérieur " à la place. Quelque chose comme ça:
Et vous pouvez également passer des arguments au constructeur ou l'initialiser avec des valeurs spécifiques, c'est très flexible, puissant et facile à implémenter ... la seule chose est que vous avez une méthode statique contenant une variable statique, pas un attribut statique ... la syntaxe change un peu, mais reste utile. J'espère que c'est utile pour quelqu'un,
Hugo González Castro.
la source
Je suppose qu'une solution simple à cela sera:
la source
Juste résolu le même truc. J'ai dû spécifier la définition d'un seul membre statique pour Singleton. Mais compliquez les choses - j'ai décidé que je ne voulais pas appeler ctor de RandClass () à moins que je ne l'utilise ... c'est pourquoi je ne voulais pas initialiser singleton globalement dans mon code. J'ai également ajouté une interface simple dans mon cas.
Voici le code final:
J'ai simplifié le code et j'utilise la fonction rand () et son initialzer srand ()
la source
Voici ma variante de la solution d'EFraim; la différence est que, grâce à l'instanciation implicite du modèle, le constructeur statique n'est appelé que si des instances de la classe sont créées, et qu'aucune définition dans le
.cpp
fichier n'est nécessaire (grâce à la magie d'instanciation de template).Dans le
.h
fichier, vous avez:Dans le
.cpp
fichier, vous pouvez avoir:Notez qu'il
MyClass::a
n'est initialisé que si la ligne [1] est là, car cela appelle (et nécessite l'instanciation de) le constructeur, qui nécessite alors l'instanciation de_initializer
.la source
Voici une autre méthode, où le vecteur est privé pour le fichier qui contient l'implémentation en utilisant un espace de noms anonyme. C'est utile pour des choses comme les tables de recherche qui sont privées pour l'implémentation:
la source
I
eti
quelque chose d'un peu plus obscur pour ne pas les utiliser accidentellement quelque part plus bas dans le fichier.Cela n'a certainement pas besoin d'être aussi compliqué que la réponse actuellement acceptée (par Daniel Earwicker). La classe est superflue. Il n'y a pas besoin d'une guerre linguistique dans ce cas.
Fichier .hpp:
Fichier .cpp:
la source
Offres GCC
https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
Marquer une méthode statique avec cet attribut et elle s'exécutera au chargement du module, avant main ().
la source
Vous définissez les variables de membre statiques de la même manière que vous définissez les méthodes de membre.
foo.h
toto.cpp
la source
Pour initialiser une variable statique, il suffit de le faire à l'intérieur d'un fichier source. Par exemple:
la source
Que diriez-vous de créer un modèle pour imiter le comportement de C #.
la source
Pour des cas simples comme ici, une variable statique enveloppée dans une fonction membre statique est presque aussi bonne. C'est simple et sera généralement optimisé par les compilateurs. Cela ne résout cependant pas le problème d'ordre d'initialisation des objets complexes.
la source
Est-ce une solution?
la source
Un constructeur statique peut être émulé en utilisant une classe amie ou une classe imbriquée comme ci-dessous.
Production:
la source
new
n'utilisez- vous un tableau de caractères que pour faire immédiatement fuir le pointeur et l'écraser !?Wow, je ne peux pas croire que personne n'ait mentionné la réponse la plus évidente, et celle qui imite le plus fidèlement le comportement du constructeur statique de C #, c'est-à-dire qu'elle n'est pas appelée tant que le premier objet de ce type n'est pas créé.
std::call_once()
est disponible en C ++ 11; si vous ne pouvez pas utiliser cela, cela peut être fait avec une variable de classe booléenne statique et une opération atomique de comparaison et d'échange. Dans votre constructeur, voyez si vous pouvez changer atomiquement l'indicateur de classe statique defalse
àtrue
, et si c'est le cas, vous pouvez exécuter le code de construction statique.Pour plus de crédit, faites-en un indicateur à trois voies au lieu d'un booléen, c'est-à-dire non exécuté, exécuté et terminé. Ensuite, toutes les autres instances de cette classe peuvent se verrouiller jusqu'à ce que l'instance exécutant le constructeur statique soit terminée (c.-à-d. Émettre une clôture mémoire, puis définir l'état sur "exécution terminée"). Votre spin-lock doit exécuter l'instruction "pause" du processeur, doubler l'attente à chaque fois jusqu'à un seuil, etc. - technique assez standard de spin-lock.
En l'absence de C ++ 11, ce devrait vous aider à démarrer.
Voici un pseudocode pour vous guider. Mettez ceci dans votre définition de classe:
Et ceci dans votre constructeur:
la source