C++, estático vs. espacio de nombres vs. singleton
static namespaces (6)
Ya leí muchas publicaciones y artículos en toda la red, pero no pude encontrar una respuesta definitiva sobre esto.
Tengo algunas funciones con propósitos similares que quiero tener fuera del alcance global. Algunos de ellos deben ser públicos, otros deben ser privados (porque solo son funciones de ayuda para los "públicos"). Además, no solo tengo funciones, sino también variables. Solo son necesarios para las funciones de ayuda "privadas" y también deben ser privadas.
Ahora hay tres formas:
- hacer una clase con todo lo que es estático (contra: potencial "No se puede llamar a la función miembro sin objeto", no todo tiene que ser estático)
- haciendo una clase de singleton (contra: necesito el objeto)
- crear un espacio de nombres (sin palabras clave privadas, ¿por qué debería ponerlo en un espacio de nombres, entonces?)
¿Cuál sería la forma de tomar para mí? ¿Posible manera de combinar algunas de estas formas?
Pensé en algo como:
- Al hacer un singleton, las funciones estáticas usan la función auxiliar del objeto singleton (¿es esto posible? Todavía estoy dentro de la clase, pero accediendo a un objeto de su tipo)
- el constructor llamado al inicio del programa, inicializa todo (-> asegurándose de que los elementos estáticos puedan acceder a las funciones desde el objeto singleton)
- acceder a las funciones públicas solo a través de MyClass :: PublicStaticFunction ()
Gracias.
¿Qué pasa con el uso de una palabra clave static
en el ámbito global (haciendo cosas locales para el archivo) como un sustituto de la privacidad?
A partir de su descripción, parece que tiene métodos y datos que interactúan entre sí aquí, en otras palabras, me parece que en realidad desea que una clase que no sea singleton mantenga el estado y ofrezca operaciones en ese estado. Exponga sus funciones públicas como la interfaz y mantenga todo lo demás privado.
Luego, puede crear instancias según sea necesario, no tiene que preocuparse por el orden de inicio o los problemas de subprocesos (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 el programa completo, puede escapar diciendo un puntero global que se establece en el método main
o posiblemente un método de instance
, pero estos vienen con sus propios conjuntos de problemas.
Como se señaló, el uso de variables globales es generalmente una mala práctica de ingeniería, a menos que sea absolutamente necesario por supuesto (mapeo de hardware, por ejemplo, pero eso no sucede TAN a menudo).
Ocultar todo en una clase es algo que haría en un lenguaje similar a Java, pero en C ++ no tiene que hacerlo, y de hecho usar espacios de nombres aquí es una alternativa superior, aunque solo sea:
- Porque la gente no creará instancias repentinas de tus objetos: ¿para qué?
- porque no se genera información de introspección (RTTI) para los espacios de nombres
Aquí hay 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 anónimo perfectamente guardado en un archivo de origen es una sección private
mejorada: no solo el cliente no puede usar lo que está dentro, sino que ni siquiera lo ve (ya que está en el archivo de origen) y, por lo tanto, no depende de él (que tiene ventajas definidas de ABI y compilación!)
La forma clásica en C de hacer esto, que parece ser lo que desea, es colocar las declaraciones de funciones públicas en un archivo de cabecera 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, solo implementalo como una clase. Creo que aquí estás haciendo una pequeña montaña.
Recuerde que la instancia de singleton de una clase de singleton es una instancia válida, por lo que es perfectamente capaz de ser el receptor de funciones miembro no estáticas. Si expone su fábrica de singleton como una función estática, tendrá todas sus funciones públicas como funciones miembro no estáticas públicas y su funcionalidad privada como funciones miembro no estáticas privadas, 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 toda la funcionalidad que está tratando de concluir está tan relacionada como para justificar que esté en la misma clase, pero si lo está, este enfoque podría funcionar.
Si adopta un enfoque "tipo C" y solo usa funciones de nivel superior, puede hacerlas privadas declarándolas en el archivo .cpp en lugar de en el archivo .h incluido públicamente. También debe hacerlos estáticos (o usar un espacio de nombres anónimo) si toma ese enfoque.
Para las funciones de ayuda pública que no dependen directamente de estas variables, hágalas funciones que no sean miembros. No hay nada ganado al ponerlos en una clase.
Para el resto, póngalo en una clase como miembros no estáticos normales. Si necesita una sola instancia de la clase accesible a nivel mundial, cree una (pero no la convierta en un singleton, solo en un global).
De lo contrario, crea una instancia cuando sea necesario.