2009-04-21 12 views
12

Tengo una clase de aplicación principal, que contiene un registrador, más algunas configuraciones de aplicaciones generales, etc.¿Cuál es la forma correcta de "C++" para hacer variables globales?

Ahora mostraré muchas ventanas de GUI y demás (que usarán el registrador y las configuraciones), y No quiero pasar el registrador y las configuraciones a cada constructor.

He visto algunas variantes, como declarar la clase principal extern en todas partes, pero eso no parece muy orientado a objetos. ¿Cuál es la forma "estándar" de C++ para hacer que los elementos en la clase principal sean accesibles para todas (o la mayoría) de las otras clases?

+3

Una discusión interesante sobre cómo implementar un singleton, junto con la seguridad de subprocesos en C++ se puede encontrar en este documento: http://www.aristeia.com /Papers/DDJ%5FJul%5FAug%5F2004%5Frevised.pdf –

Respuesta

12

Utilice singleton design pattern.

Básicamente, devuelve una instancia estática de un objeto y la utiliza para todo su trabajo.

favor ver este link about how to use a singleton y también esta stackoverflow link about when you should not use it

Advertencia: El patrón Singleton implica la promoción estado global. El estado global es malo por muchas razones.
Por ejemplo: pruebas unitarias.

+1

¡Pero tenga cuidado! Utilice sus Singletons sabiamente: http://www.ibm.com/developerworks/webservices/library/co-single.html – toxvaerd

+0

Vea también: http://stackoverflow.com/questions/137975/what-is-so-bad- about-singletons – Reunanen

+0

Gracias chicos, actualicé mi respuesta para incluir estos 2 enlaces. –

0

Creo que Service Locator hará. Que tendrá que pasar en constructores o tener una función de miembro estático accesible globalmente en algún lugar conocido. La primera opción es mucho más preferible.

+0

Un Singleton con otro nombre ... –

7

No es una mala idea pasar el registrador y la configuración a todos los constructores si el registrador y la configuración son suficientemente abstractos.

Singleton puede ser un problema en el futuro. Pero parece una elección correcta en el proyecto. Tu elección. Si su proyecto es lo suficientemente pequeño, vaya con singleton. Si no, inyección de dependencia.

+0

Si acaba de agregar a un archivo puede no ser tan malo, pero si tiene que inicializar un marco de trabajo de registro, es posible que no desee reiniciarlo siempre. –

+1

reiniciar? ¿Por qué? Usted crea una vez en la parte superior y la pasa al final a todos los servicios que la necesitan. –

+0

Lo siento, leí mal "No es una mala idea pasar el registrador y la configuración a todos los constructores ..." –

0

No sé si esto es útil en su caso o no, pero en MFC, había/hay una clase de aplicación.

Solía ​​tirar cosas como esta en esa clase.

Supongo que no está utilizando MFC, pero si tiene una clase de aplicación o algo similar, podría ser útil.

0

Evitaría el patrón singleton.
Demasiados problemas cuando se trata de pruebas y todo lo que (ver What is so bad about singletons?)

Personalmente me gustaría pasar el registrador, etc en el constructor. Alternativamente, puede usar una fábrica para crear/pasar una referencia al recurso.

+0

Ejecutado correctamente, no hay diferencia entre utilizar un singleton disponible en cualquier lugar donde use su #include y sus alternativas, excepto que con su alternativa debe pasar una referencia en todos los niveles. – kmarsh

5

¿Por qué no utilizar el sistema que ya está en su lugar? Es decir, redirigir std :: clog para enviar a un archivo y escribir en std :: clog.

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

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

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

pierde el formato coherente (definido en un lugar) de un registrador real, y posiblemente también pierda funciones de utilidad para generar cierta información no estándar (es decir, no hay conversión de cadenas). pero para un proyecto pequeño, esta es una forma realmente rápida y fácil de hacerlo. – rmeador

+1

Incluso si no desea utilizar std :: clog, aún puede aprender de ello. clog es una variable global. Si quiere su propio registrador, conviértalo en una variable global. – jalf

+0

@jalf: en realidad usa el "Construir en el primer uso" -Idiom para crear una instancia solo cuando sea necesario. –

0

¿Por qué no utilizar log4cxx? Tales problemas se resuelven hace mucho tiempo y son ampliamente utilizados por muchos. A menos que esté construyendo un sistema de registro propio muy especial ... En tal caso, utilizaría un patrón Factory que crearía registradores para cualquier persona interesada (o regalaría una instancia existente si es singleton). Otras clases utilizarían fábrica para obtener el registrador. Pasar los registradores en los parámetros del constructor es una mala idea, porque combina tu clase con el registrador.

3

Estoy de acuerdo con algún tipo de enfoque singleton. Definitivamente no quiere pasar objetos de registrador por todos lados. Eso será muy aburrido muy rápido, y en mi humilde opinión es un peor diseño que simplemente tener un objeto global simple.

Una buena prueba de si tiene una buena solución son los pasos necesarios para que el registro funcione en una función que lo necesita.

Si usted tiene que hacer mucho más que

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

entonces usted está perdiendo esfuerzo.

1

Logging cae bajo el ámbito de la 'separación de preocupación' como en aspect orient programming

el registro no es generalmente una función o preocupación de un objeto (por ejemplo, que no cambia el estado del objeto, sino que es meramente un mecanismo para observar/registrar el estado, y el resultado es esencialmente desechable en la mayoría de los contextos) Es una función secundaria efímera y, a menudo opcional, que no contribuye al funcionamiento de una clase. El método de un objeto puede realizar el registro, pero el registro puede realizarse allí porque es un lugar conveniente para hacerlo o ese punto en la secuencia de ejecución del código es donde se desea que se registre el estado.

Debido a que C++ no proporciona las facilidades para definir los aspectos, tiendo a simplemente mantener los objetos efímeros esencialmente externos como los registradores globales y envolverlos en un espacio de nombres para contenerlos de algún modo. Los espacios de nombres no están destinados a la contención, por lo que es bastante feo, pero a falta de cualquier otra cosa es conveniente y mucho menos feo e inconsecuente que pasar los registradores en parámetros formales o hacer referencia a ellos en todos los objetos que desea registrar. Esto también facilita la eliminación del registrador si en algún momento decido que ya no necesito el registrador (es decir, si solo se utilizó para la depuración).

+0

del mismo modo, tenerlo global en un espacio de nombres permite una implementación más fácil de un mechnisim de bloqueo para aplicaciones de subprocesos múltiples. –

0

simplemente pasan a su clase principal en el constructor de las otras clases que desea tener acceso a "todo"

A continuación, puede proporcionar acceso al registrador, etc a través de propiedades de miembro. (Perdonar mi sintaxis de C++, esto es solo un lenguaje inventado llamado "C++ confundido por VB")

p.

Class App { 
    Private m_logger; 
    Private m_config; 

    Public logger() { 
     return m_logger; 
    } 

    Public config() { 
     return m_config 
    } 
} 

Class Window1 { 
    New(anApp) { 
    } 
    .... 
} 
0

¿Por qué nadie ha pensado en el patrimonio y el polimorfismo? También podría utilizar una fábrica abstracta con ese singleton;)

Cuestiones relacionadas