Question Quel est le bon "moyen C ++" pour faire des variables globales?


J'ai une classe d'application principale, qui contient un enregistreur, plus quelques configurations d'application générales, etc.

Maintenant, je vais afficher beaucoup de fenêtres d'interface graphique et ainsi de suite (qui utiliseront le journal et les configs), et je ne veux pas transmettre l'enregistreur et les configurations à chaque constructeur.

J'ai vu certaines variantes, comme déclarer la classe principale extern partout, mais cela ne semble pas très orienté objet. Qu'est-ce que le moyen C ++ "standard" pour rendre les éléments de la classe principale accessibles à toutes (ou à la plupart) les autres classes?


12
2018-04-21 13:58


origine


Réponses:


Utilisez le modèle de conception singleton.

En gros, vous retournez une instance statique d'un objet et l'utilisez pour tout votre travail.

S'il vous plaît voir ceci lien sur la façon d'utiliser un singleton et aussi ce lien stackoverflow à propos du moment où vous ne devriez pas l'utiliser

Avertissement: Le modèle singleton implique la promotion de l'état global. L'état mondial est mauvais pour de nombreuses raisons.
Par exemple: tests unitaires.


12
2018-04-21 14:00



Ce n'est pas une mauvaise idée de passer le journal et la configuration à tous les constructeurs si votre enregistreur et votre configuration sont suffisamment abstraits.

Singleton peut être un problème dans le futur. Mais il semble que le bon choix commence dans le projet. Votre choix. Si votre projet est assez petit, optez pour singleton. Si non - injection de dépendance.


7
2018-04-21 14:03



Pourquoi ne pas utiliser le système qui est déjà en place? C'est-à-dire rediriger std :: clog pour générer un fichier et écrire sur std :: clog.

std::fstream *f = new std::fstream("./my_logfile.log")

std::clog.rdbuf(f->rdbuf());

std::clog << "Line of log information" << std::endl;

5
2018-04-21 15:11



Je suis d'accord avec une sorte d'approche singleton. Vous ne voulez certainement pas laisser passer des objets Logger partout. Cela deviendra très vite ennuyeux, et IMHO est un concept pire que d'avoir un simple objet global.

Un bon test pour savoir si vous avez une bonne solution est la marche à suivre pour que la journalisation fonctionne dans une fonction qui en a besoin.

Si vous devez faire beaucoup plus que

#include "Logger.h"
...
void SomeFunction()
{
    ...
    LOGERROR << "SomeFunction is broken";   
    ...
}
...

alors vous gaspillez votre effort.


3
2018-04-21 16:16



La journalisation relève de la «séparation des préoccupations» comme dans programmation de l'orientation

Généralement, l'enregistrement n'est pas une fonction ou une préoccupation d'un objet (par exemple, il ne modifie pas l'état de l'objet; il s'agit simplement d'un mécanisme d'observation / d'enregistrement de l'état et la sortie est essentiellement disponible dans la plupart des contextes) C'est une fonction latérale éphémère et souvent optionnelle qui ne contribue pas au fonctionnement d'une classe. La méthode d'un objet peut effectuer la journalisation, mais la journalisation peut être effectuée là parce que c'est un endroit pratique pour le faire ou que le point dans le flux d'exécution de code est celui où l'on souhaite que l'état soit enregistré.

Comme C ++ ne permet pas de définir les aspects, j'ai tendance à simplement garder les objets éphémères essentiellement externes tels que les enregistreurs globaux et à les envelopper dans un espace de noms pour les contenir. Les espaces de noms ne sont pas destinés au confinement, donc c'est plutôt moche, mais à défaut, il est pratique et beaucoup moins moche et peu intéressant que de passer des enregistreurs dans des paramètres formels ou de les référencer dans tous les objets à consigner. Cela facilite également le retrait de l’enregistreur si, à un moment donné, je décide de ne plus avoir besoin de l’enregistreur (c’est-à-dire s’il n’était utilisé que pour le débogage).


1
2018-04-25 08:36



j'imagine Localisateur de service ça ira. Que vous deviez soit faire circuler dans des constructeurs, soit avoir une fonction membre statique accessible globalement dans un emplacement bien connu. La première option est beaucoup plus préférable.


0
2018-04-21 14:00



Je ne sais pas si cela est utile dans votre situation ou non, mais dans MFC, il y avait / est une classe d'application.

J'utilise pour lancer des choses comme ça dans cette classe.

Je suppose que vous n'utilisez pas MFC, mais si vous avez une classe d'application ou quelque chose de similaire, cela peut être utile.


0
2018-04-21 14:09



J'éviterais le modèle singleton.
Trop de problèmes pour les tests et tout ça (voir Qu'est-ce qui fait si mal aux singletons?)

Personnellement, je passerais le logger etc. dans le constructeur. Vous pouvez également utiliser une fabrique pour créer / transmettre une référence à la ressource.


0
2018-04-21 15:03



Pourquoi ne pas utiliser log4cxx? Ces problèmes sont résolus depuis longtemps et largement utilisés par beaucoup. A moins que vous ne construisiez un système de journalisation très spécial ... Dans un tel cas, j'utiliserais un pattern Factory qui créerait des loggers pour toute personne intéressée (ou donnerait une instance existante si elle est singleton). D'autres classes utiliseraient l'usine pour obtenir l'enregistreur. Passer des enregistreurs dans les paramètres du constructeur est une mauvaise idée, car il associe votre classe à un enregistreur.


0
2018-04-21 15:18