La pregunta ¿Dónde debería poner funciones que no están relacionadas con una clase ha provocado cierto debate sobre si tiene sentido en C ++ combinar funciones de utilidad en una clase o simplemente hacer que existan como funciones libres en un espacio de nombres?
Vengo de un fondo de C # donde la última opción no existe y, por lo tanto, naturalmente tiendo a usar clases estáticas en el pequeño código de C ++ que escribo. La respuesta más votada sobre esa pregunta, así como varios comentarios, dicen que las funciones libres son preferibles, incluso sugiriendo que las clases estáticas eran un antipatrón. ¿Por qué es así en C ++? Al menos en la superficie, los métodos estáticos en una clase parecen indistinguibles de las funciones libres en un espacio de nombres. ¿Por qué así la preferencia por este último?
¿Serían diferentes las cosas si la colección de funciones de utilidad necesitara datos compartidos, por ejemplo, un caché que uno pudiera almacenar en un campo estático privado?
fuente
Respuestas:
Supongo que para responder que debemos comparar las intenciones de las clases y los espacios de nombres. De acuerdo con Wikipedia:
Clase
Espacio de nombres
Ahora, ¿qué estás tratando de lograr al poner las funciones en una clase (estáticamente) o un espacio de nombres? Apostaría a que la definición de un espacio de nombres describe mejor su intención: todo lo que desea es un contenedor para sus funciones. No necesita ninguna de las características descritas en la definición de clase. Tenga en cuenta que las primeras palabras de la definición de clase son " En la programación orientada a objetos ", sin embargo, no hay nada orientado a objetos en una colección de funciones.
Probablemente también hay razones técnicas, pero como alguien que viene de Java y trata de entender el lenguaje de múltiples paradigmas que es C ++, la respuesta más obvia para mí es: Porque no necesitamos OO para lograr esto.
fuente
Sería muy cauteloso al llamar a eso un antipatrón. Por lo general, se prefieren los espacios de nombres, pero como no hay plantillas de espacios de nombres y los espacios de nombres no se pueden pasar como parámetros de plantilla, el uso de clases con nada más que miembros estáticos es bastante común.
fuente
En el pasado necesitaba tomar una clase FORTRAN. Conocía otros idiomas imperativos para entonces, así que pensé que podía hacer FORTRAN sin estudiar mucho. Cuando entregué mi primera tarea, el profesor me la devolvió y me pidió que la volviera a hacer: dijo que los programas Pascal escritos en sintaxis FORTRAN no cuentan como presentaciones válidas.
Un problema similar está en juego aquí: el uso de clases estáticas para alojar funciones de utilidad en C ++ es un lenguaje extraño para C ++.
Como mencionó en su pregunta, el uso de clases estáticas para funciones de utilidad en C # es una necesidad: las funciones independientes simplemente no son una opción en C #. El lenguaje necesario para desarrollar un patrón que permita a los programadores definir funciones independientes de alguna otra manera, es decir, dentro de las clases de utilidad estática. Este fue un truco de Java tomado palabra por palabra: por ejemplo, java.lang.Math y System.Math de .NET son casi isomórficos.
C ++, sin embargo, ofrece espacios de nombres, una instalación diferente para lograr el mismo objetivo, y lo utiliza activamente en la implementación de su biblioteca estándar. Agregar una capa adicional de clases estáticas no solo es innecesario, sino también algo intuitivo para los lectores sin C # o fondo Java. En cierto sentido, está introduciendo una "traducción de préstamo" en el idioma para algo que se puede expresar de forma nativa.
Cuando sus funciones necesitan compartir datos, la situación es diferente. Debido a que sus funciones ya no están relacionadas , el patrón Singleton se convierte en la forma preferida de abordar este requisito.
fuente
¿Quizás necesites preguntar por qué querrías una clase totalmente estática?
La única razón por la que puedo pensar es que otros lenguajes (Java y C #) que son mucho 'todo es una clase' los requieren. Estos lenguajes no pueden crear funciones de nivel superior, por lo que inventaron un truco para mantenerlos, y esa fue la función miembro estática. Son una solución alternativa, pero C ++ no necesita tal cosa, puede crear directamente nuevas funciones independientes de alto nivel.
Si necesita funciones que operan en un elemento de datos específico, entonces tiene sentido agruparlas en una clase que contenga los datos, pero luego, dejan de ser funciones y comienzan a ser miembros de esa clase que operan en los datos de la clase.
Si tiene una función que no opera en un tipo de datos en particular (uso la palabra aquí ya que las clases son formas de definir nuevos tipos de datos), entonces es realmente un antipatrón empujarlos a una clase, para nada más que fines semánticos
fuente
En otras palabras, tener una clase en lugar de un espacio de nombres no tiene ventajas.
Por un lado, le ahorra escribir
static
todo el tiempo, aunque podría decirse que es un beneficio menor.El principal beneficio es que es la herramienta menos poderosa para el trabajo. Las clases se pueden usar para crear objetos, se pueden usar como el tipo de variables o como argumentos de plantilla. Ninguna de esas son características que desea para su colección de funciones. Por lo tanto, es preferible usar una herramienta que no tenga esas características, de modo que la clase no pueda ser mal utilizada accidentalmente.
A partir de eso, el uso de un espacio de nombres también deja en claro de inmediato a los usuarios de su código que se trata de una colección de funciones y no un plan para crear objetos.
fuente
Una clase totalmente estática hará el trabajo, pero es como conducir un camión de 53 pies al supermercado para comprar papas fritas y salsa cuando lo hará un sedán de cuatro puertas (es decir, es excesivo). Las clases vienen con una pequeña cantidad de gastos adicionales y su existencia podría dar a alguien la impresión de que crear una instancia podría ser una buena idea. Las funciones gratuitas que ofrece C ++ (y C, donde todas las funciones son gratuitas) no lo hacen; son solo funciones y nada más.
Realmente no. El propósito original de
static
en C (y luego C ++) era ofrecer almacenamiento persistente que se pueda utilizar en cualquier nivel de alcance:Puede llevar el alcance al nivel de un archivo, lo que lo hace visible para todos los ámbitos más estrechos pero no fuera del archivo:
Un miembro privado de clase estática en C ++ tiene el mismo propósito pero está limitado al alcance de una clase. La técnica utilizada en el
counter()
ejemplo anterior también funciona dentro de los métodos de C ++ y es algo que realmente recomendaría hacer si la variable no necesita ser visible para toda la clase.fuente
Si una función no mantiene un estado y es reentrante, no parece tener mucho sentido meterla dentro de una clase (a menos que el idioma lo obligue). Si la función mantiene algún estado (por ejemplo, solo puede hacerse segura para subprocesos mediante un mutex estático), entonces los métodos estáticos en una clase parecen apropiados.
fuente
Gran parte del discurso sobre el tema aquí tiene sentido, aunque hay algo muy fundamental sobre C ++ que hace que
namespaces
yclass
en /struct
s muy diferente.Las clases estáticas (clases donde todos los miembros son estáticos, y la clase nunca se instanciará) son en sí mismas objetos. No son simplemente un
namespace
funciones para contener.La metaprogramación de plantillas nos permite utilizar una clase estática como objeto de tiempo de compilación.
Considera esto:
Para usarlo necesitamos funciones contenidas dentro de una clase. Un espacio de nombres no funcionará aquí. Considerar:
Ahora para usarlo:
Siempre que un nuevo asignador exponga un
allocate
release
función y que sea compatible, cambiar a un nuevo asignador es fácil.Esto no se puede lograr con espacios de nombres.
¿Siempre necesitas funciones para ser parte de una clase? No.
¿Usar una clase estática es un antipatrón? Depende del contexto.
En ese caso, es probable que lo que intente lograr sea mejor a través de la programación orientada a objetos.
fuente
Como John Carmack dijo:
"A veces, la implementación elegante es solo una función. No es un método. No es una clase. No es un marco. Solo una función".
Creo que eso lo resume bastante bien. ¿Por qué lo convertirías con fuerza en una clase si claramente no es una clase? C ++ tiene el lujo de que realmente puedes usar funciones; En Java, todo es un método. Entonces necesitas clases de utilidad, y muchas de ellas.
fuente