C++, statique vs espace de noms vs singleton
J'ai déjà lu beaucoup de messages et d'articles sur le net, mais je n'ai pas trouvé de réponse définitive à ce sujet.
J'ai certaines fonctions à des fins similaires que je veux avoir hors de la portée globale. Certains d'entre eux ont besoin que soit public, d'autres devraient être privés (car ce ne sont que des fonctions d'aide pour les "publics"). De plus, je n'ai pas seulement des fonctions, mais aussi des variables. Ils ne sont nécessaires que par les fonctions d'assistance "privées" et devraient être privé, trop.
Maintenant, il y a les trois façons:
- faire une classe avec tout étant statique (contre: potentiel "ne peut pas appeler la fonction membre sans objet" - tout ne doit pas être statique)
- faire une classe singleton (contre: j'aurai besoin de l'objet)
- Faire un espace de noms (Pas de mot-clé privé-Pourquoi devrais-je le mettre dans un espace de noms, alors?)
Quelle serait la façon de prendre pour moi? Possible de combiner certains de ces des moyens?
J'ai pensé à quelque chose comme:
- en faisant un singleton, les fonctions statiques utilisent la fonction d'aide de l'objet singleton (est-ce possible? Je suis toujours dans la classe, mais j'accède à un objet de son type)
- constructeur appelé au démarrage du programme, initialise tout (- >s'assurer que la statique peut accéder aux fonctions de l'objet singleton)
- accéder aux fonctions publiques uniquement par Maclasse::PublicStaticFunction()
Merci.
6 réponses
Comme indiqué, l'utilisation de variables globales est généralement une mauvaise pratique d'ingénierie, sauf si absolument nécessaire bien sûr (mappage de matériel par exemple, mais cela n'arrive pas si souvent).
Stocker tout dans une classe est quelque chose que vous feriez dans un langage de type Java, mais en C++ vous n'avez pas à le faire, et en fait utiliser des espaces de noms ici est une alternative supérieure, si seulement:
- parce que les gens ne construiront pas soudainement des instances de vos objets: à quelle fin ?
- parce que non les informations d'introspection (RTTI) sont générées pour les espaces de noms
Voici une implémentation typique:
// foo.h
#ifndef MYPROJECT_FOO_H_INCLUDED
#define MYPROJECT_FOO_H_INCLUDED
namespace myproject {
void foo();
void foomore();
}
#endif // MYPROJECT_FOO_H_INCLUDED
// foo.cpp
#include "myproject/foo.h"
namespace myproject {
namespace {
typedef XXXX MyHelperType;
void bar(MyHelperType& helper);
} // anonymous
void foo() {
MyHelperType helper = /**/;
bar(helper);
}
void foomore() {
MyHelperType helper = /**/;
bar(helper);
bar(helper);
}
} // myproject
L'espace de noms anonyme soigneusement niché dans un fichier source est une section private
améliorée: non seulement le client ne peut pas utiliser ce qui est à l'intérieur, mais il ne le voit même pas du tout (puisqu'il est dans le fichier source) et n'en dépend donc pas (ce qui a des avantages ABI et compile-time!)
Pour les fonctions d'aide publique qui ne dépendent pas directement de ces variables, faites-en des fonctions non-membres. Il n'y a rien à gagner en les mettant dans une classe.
Pour le reste, placez - le dans une classe en tant que membres non statiques normaux. Si vous avez besoin d'une seule instance globalement accessible de la classe, créez-en une (mais n'en faites pas un singleton, juste un global).
Sinon, instanciez-le si nécessaire.
La façon classique de faire cela, qui semble être ce que vous voulez, est de mettre les déclarations de fonction publique dans un fichier d'en-tête, et toute l'implémentation dans le fichier source, rendant les variables et les fonctions non publiques statiques. Sinon, implémentez-le simplement en tant que classe - je pense que vous faites un peu une montagne à partir d'une taupinière ici.
Qu'en est-il de l'utilisation d'un mot clé static
à portée globale (rendant les choses locales dans le fichier) en tant que substitut de la vie privée?
D'après votre description, il semble que vous ayez des méthodes et des données qui interagissent les unes avec les autres ici, en d'autres termes, il me semble que vous voulez réellement une classe non-singleton pour maintenir l'état et offrir des opérations sur cet état. Exposez vos fonctions publiques en tant qu'interface et gardez tout le reste privé.
Ensuite, vous pouvez créer une(des) instance (s) au besoin, vous n'avez pas à vous soucier des problèmes d'ordre d'initialisation ou de threading (si vous en avez un par thread), et seuls les clients qui ont besoin access aura un objet sur lequel opérer. Si vous avez vraiment besoin d'un seul de ceux-ci pour l'ensemble du programme, vous pouvez vous en sortir, par exemple un pointeur global défini dans main
ou éventuellement une méthode instance
, mais ceux-ci viennent avec leurs propres problèmes.
Rappelez-vous que l'instance singleton d'une classe singleton est une instance valide, elle est donc parfaitement capable d'être le destinataire de fonctions membres non statiques. Si vous exposez votre fabrique singleton en tant que fonction statique, alors toutes vos fonctionnalités publiques en tant que fonctions membres non statiques publiques et votre fonctionnalité privée en tant que fonctions membres non statiques privées, toute personne pouvant accéder à la classe peut accéder à la fonctionnalité publique en invoquant simplement la fabrique singleton fonction.
Vous ne décrivez pas si toutes les fonctionnalités que vous essayez de terminer sont aussi liées que pour justifier d'être dans la même classe, mais si c'est le cas, cette approche pourrait fonctionner.
Si vous prenez une approche "C-like" et utilisez simplement des fonctions de niveau supérieur, vous pouvez les rendre privées en les déclarant dans le .fichier cpp plutôt que le public inclus .h fichier. Vous devriez également les rendre statiques (ou utiliser un espace de noms anonyme) si vous adoptez cette approche.