2011-04-26 9 views
23

Ya leí muchas publicaciones y artículos en toda la red, pero no pude encontrar una respuesta definitiva al respecto.C++, static vs. namespace vs. singleton

Tengo algunas funciones con propósitos similares que quiero tener fuera del alcance global. Algunos de ellos necesitan para ser públicos, otros deben ser privados (porque son solo funciones auxiliares para los "públicos"). Además, no tengo solo funciones, sino también variables. Solo son necesarios para las funciones auxiliares "privadas" y también deben ser privadas.

Ahora bien, hay tres maneras:

  • haciendo una clase con todo ser estáticas (contra: potencial "No se puede llamar a la función miembro sin objeto" - no todo tiene que ser estática)
  • hacer un producto único clase (en contra de: i tendrá el objeto)
  • hacer un espacio de nombres (sin palabra clave private - ¿por qué debería ponerlo en un espacio de nombres en absoluto, entonces?)

¿Cuál sería la manera de tomar por mí? ¿Posible forma de combinar algunas de estas formas?

pensé en algo así como:

  1. hacer un producto único, las funciones estáticas utilizan la función de ayuda del objeto Singleton (es esto posible todavía estoy dentro de la clase, pero el acceso a un objeto de ella es? tipo)
  2. constructor llamado al inicio programm, inicializa todo (-> asegurándose de que la estática pueden acceder a las funciones del objeto Singleton)
  3. acceso a las funciones públicas sólo a través de MyClass :: PublicStaticFunction()

Gracias.

+4

No utilizar singletons a menos que yo usted realmente necesita (es decir. casi nunca). Una buena discusión es http://www.ibm.com/developerworks/webservices/library/co-single/index.html –

Respuesta

20

Como se señaló, el uso de variables globales generalmente es una mala práctica de ingeniería, a menos que sea absolutamente necesario, por supuesto (hardware de mapeo, por ejemplo, pero eso no sucede ESO a menudo).

Stashing todo en una clase es algo que haría en un lenguaje similar a Java, pero en C++ que no tiene que hacerlo, y de hecho el uso de espacios de nombres aquí es una alternativa superior, aunque sólo sea:

  • porque la gente no creará repentinamente instancias de sus objetos: ¿con qué fin?
  • porque no hay información introspección (RTTI) se genera para los espacios de nombres

Aquí es una implementación típica:

// 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 

El espacio de nombres en el anonimato cuidadosamente escondido en un archivo de origen es un private sección mejorada: no sólo el cliente no puede usar lo que está adentro, pero ni siquiera lo ve (ya que está en el archivo fuente) y por lo tanto no depende de él (que tiene ventajas definidas de ABI y tiempo de compilación!)

+2

Gracias. Decidí que esta era la mejor solución para mi problema. Vengo de C# (donde todo es una clase), es por eso que estas soluciones de espacios de nombres (sin nombre) son nuevas para mí. – blubberbernd

+0

@blubberbernd: en este caso, solo puedo recomendar un buen libro de C++. C++ es rico y lleno de (malas) sorpresas, y un buen tutorial solo puede ayudar. Hay una lista en SO: http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list –

+0

Buena respuesta. Estoy haciendo algo de programación incrustada en C++ y me enfrenté al problema de que algunos periféricos simplemente pueden ser utilizados (deberían inicializarse) una vez. Fue algo natural de implementar en C, pero sentí que tenía que elegir un enfoque orientado a objetos usando C++. Pero usar un singleton fue de uso limitado porque también tuve que implementar rutinas de servicio de interrupción relacionadas como "funciones gratuitas". –

2

La forma clásica C de hacer esto, que parece ser lo que desea, es poner las declaraciones de funciones públicas en un archivo de encabezado y toda la implementación en el archivo fuente, haciendo que las variables y las funciones no públicas sean estáticas. De lo contrario, simplemente impleméntalo como una clase. Creo que estás haciendo una montaña desde aquí.

+2

Tenga en cuenta que el uso de 'static' de esta manera está en desuso en C++ a favor de los espacios de nombres anónimos. Entonces 'namespace {int i; } 'en lugar de' static int i; 'De lo contrario, sí. –

+0

@Dennis Stroustrup estaba hablando de dejar de interpretarlo hace algún tiempo, lo que creo que es lo correcto. No sé si alguna vez salió algo de eso. Encuentro lo del espacio de nombres sin nombre, bueno ... tonto. –

+1

Personalmente, considero 'estático' tener tres significados completamente sin relación tontos. Pero mirando a través del borrador C++ 0x, parecen haber eliminado ese bit. Así que no importa :-) –

1

¿Qué tal el uso de una palabra clave static en alcance global (hacer cosas locales en el archivo) como un sustituto de la privacidad?

6

Don't make it a singleton

Para funciones de ayuda públicos que no dependen directamente de estas variables, los hacen funciones que no son miembros. No hay nada ganado poniéndolos en una clase.

Para el resto, póngalo en una clase como miembros no estáticos normales. Si necesita una única instancia de la clase accesible a nivel mundial, cree una (pero no la convierta en una instancia única, solo global).

De lo contrario, cree una instancia cuando sea necesario.

+0

Sí, votaciones anónimas. ¿Alguien quiere explicar * por qué * esta es una mala respuesta? – jalf

+1

No soy el que menosprecia, pero supongo que algunos pueden tener problemas con su párrafo de "instancia accesible globalmente".Los objetos globales sufren las mismas desventajas que los singletons (ya que los singletons son simplemente objetos globales disfrazados). –

+1

Otro punto de controversia podría ser "No hay nada ganado poniéndolos en una clase". Hay una cosa ganada, aunque sea trivial: la clase que contiene las funciones miembro estáticas sirve como espacio de nombres. Me doy cuenta de que el mismo efecto se puede lograr con 'namespace', pero quizás las personas que provienen de un fondo Java no lo hacen. –

0

Recuerde que la instancia singleton de una clase singleton es una instancia válida, por lo que es perfectamente capaz de ser el destinatario de las funciones miembro no estáticas.Si expone su fábrica de singleton como una función estática y tiene todas sus funciones públicas como funciones públicas no estáticas y su funcionalidad privada como funciones privadas no estáticas, cualquiera que pueda acceder a la clase puede acceder a la funcionalidad pública simplemente invocando la fábrica singleton. función.

No describe si todas las funciones que está tratando de concluir están relacionadas como para justificar estar en la misma clase, pero si lo hace, este enfoque podría funcionar.

Si adopta un enfoque tipo "C" y solo utiliza funciones de nivel superior, puede hacerlo privado declarándolo en el archivo .cpp en lugar del archivo .h incluido públicamente. También debe hacerlos estáticos (o usar un espacio de nombre anónimo) si toma ese enfoque.

1

Según su descripción, parece que tiene métodos y datos que interactúan entre sí aquí, en otras palabras, me parece que realmente desea una clase no única para mantener el estado y ofrecer operaciones en ese estado. Exponga sus funciones públicas como interfaz y mantenga todo lo demás en privado.

Luego puede crear instancias según sea necesario, no tiene que preocuparse por los problemas de orden init o de subprocesamiento (si tiene uno por subproceso), y solo los clientes que necesitan acceso tendrán un objeto para operar . Si realmente necesita solo uno de estos para todo el programa, puede alejarse, digamos un puntero global establecido en main o posiblemente un método instance, pero estos vienen con sus propios conjuntos de problemas.