miembros estaticos estaticas c++ oop class syntax static

estaticos - ¿Cómo creas una clase estática en C++?



miembros estaticos c++ (12)

Si está buscando una forma de aplicar la palabra clave "estática" a una clase, como puede hacerlo en C # por ejemplo

las clases estáticas son solo el compilador que lo detiene y le impide escribir cualquier método / variable de instancia.

Si solo escribes una clase normal sin ningún método / variable de instancia, es lo mismo, y esto es lo que harías en C ++

¿Cómo creas una clase estática en C ++? Debería poder hacer algo como:

cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;

Suponiendo que he creado la clase BitParser . ¿Cómo sería la definición de la clase BitParser ?


A diferencia de otros lenguajes de programación administrados, "clase estática" NO tiene significado en C ++. Puede hacer uso de la función miembro estática.


Como se ha señalado aquí, una mejor manera de lograr esto en C ++ podría ser usar espacios de nombres. Pero como nadie ha mencionado la palabra clave final aquí, estoy publicando el aspecto de un equivalente directo de static class de C # en C ++ 11 o posterior:

class BitParser final { public: BitParser() = delete; static bool GetBitAt(int buffer, int pos); }; bool BitParser::GetBitAt(int buffer, int pos) { // your code }


Considere la solución de Matt Price .

  1. En C ++, una "clase estática" no tiene ningún significado. Lo más cercano es una clase con solo métodos y miembros estáticos.
  2. Usar métodos estáticos solo te limitará.

Lo que desea es, expresado en semántica de C ++, colocar su función (ya que es una función) en un espacio de nombres.

Editar 2011-11-11

No hay "clase estática" en C ++. El concepto más cercano sería una clase con solo métodos estáticos. Por ejemplo:

// header class MyClass { public : static void myMethod() ; } ; // source void MyClass::myMethod() { // etc. }

Pero debe recordar que las "clases estáticas" son hacks en el tipo de lenguajes similares a Java (por ejemplo, C #) que no pueden tener funciones que no sean miembros, por lo que tienen que moverlas dentro de clases como métodos estáticos.

En C ++, lo que realmente desea es una función que no sea miembro que declarará en un espacio de nombres:

// header namespace MyNamespace { void myMethod() ; } // source namespace MyNamespace { void myMethod() { // etc. } }

¿Porqué es eso?

En C ++, el espacio de nombres es más poderoso que las clases para el patrón "método estático de Java", porque:

  • Los métodos estáticos tienen acceso a las clases de símbolos privados.
  • Los métodos estáticos privados siguen siendo visibles (si son inaccesibles) para todos, lo que rompe un poco la encapsulación.
  • Los métodos estáticos no pueden ser declarados hacia adelante
  • el usuario de la clase no puede sobrecargar los métodos estáticos sin modificar el encabezado de la biblioteca
  • no hay nada que pueda hacerse mediante un método estático que no pueda hacerse mejor que una función no miembro (posiblemente amiga) en el mismo espacio de nombres
  • los espacios de nombres tienen su propia semántica (se pueden combinar, pueden ser anónimos, etc.)
  • etc.

Conclusión: No copie / pegue el patrón de Java / C # en C ++. En Java / C #, el patrón es obligatorio. Pero en C ++, es un mal estilo.

Editar 2010-06-10

Hubo un argumento a favor del método estático porque a veces, uno necesita usar una variable miembro privada estática.

Estoy en desacuerdo, como se muestra a continuación:

La solución "miembro privado estático"

// HPP class Foo { public : void barA() ; private : void barB() ; static std::string myGlobal ; } ;

Primero, myGlobal se llama myGlobal porque sigue siendo una variable privada global. Un vistazo a la fuente de CPP aclarará que:

// CPP std::string Foo::myGlobal ; // You MUST declare it in a CPP void Foo::barA() { // I can access Foo::myGlobal } void Foo::barB() { // I can access Foo::myGlobal, too } void barC() { // I CAN''T access Foo::myGlobal !!! }

A primera vista, el hecho de que la función gratuita barC no puede acceder a Foo :: myGlobal parece algo bueno desde el punto de vista de la encapsulación ... Es genial porque alguien que mira el HPP no podrá (a menos que recurrir al sabotaje) acceder Foo :: myGlobal.

Pero si lo observa detenidamente, encontrará que es un error colosal: no solo su variable privada debe declararse en el HPP (y, por lo tanto, visible para todo el mundo, a pesar de ser privada), sino que debe declarar en el mismo HPP todas las funciones (como en TODAS) que estarán autorizadas para acceder a él!

Por lo tanto, usar un miembro estático privado es como caminar desnudo con la lista de tus amantes tatuados en tu piel: nadie está autorizado a tocar, pero todos pueden echar un vistazo. Y el bono: Todos pueden tener los nombres de los autorizados para jugar con sus secretos.

private hecho private ... :-D

La solución "espacios de nombres anónimos"

Los espacios de nombres anónimos tendrán la ventaja de hacer que las cosas sean realmente privadas.

Primero, el encabezado de HPP

// HPP namespace Foo { void barA() ; }

Solo para asegurarse de que comentó: No hay una declaración inútil de barB ni myGlobal. Lo que significa que nadie que lea el encabezado sabe lo que se esconde detrás de barA.

Entonces, el CPP:

// CPP namespace Foo { namespace { std::string myGlobal ; void Foo::barB() { // I can access Foo::myGlobal } } void barA() { // I can access myGlobal, too } } void barC() { // I STILL CAN''T access myGlobal !!! }

Como puede ver, al igual que la declaración de "clase estática", fooA y fooB todavía pueden acceder a myGlobal. Pero nadie más puede. ¡Y nadie más fuera de este CPP sabe que fooB y myGlobal incluso existen!

A diferencia de la "clase estática" que camina desnuda con su libreta de direcciones tatuada en su piel, el espacio de nombres "anónimo" está completamente vestido , lo que parece un AFAIK bastante mejor encapsulado.

¿Realmente importa?

A menos que los usuarios de su código sean saboteadores (le permitiré, como ejercicio, descubrir cómo se puede acceder a la parte privada de una clase pública utilizando un comportamiento sucio, truco indefinido ...), lo private es private , incluso si es visible en la sección private de una clase declarada en un encabezado.

Sin embargo, si necesita agregar otra "función privada" con acceso al miembro privado, debe declararlo a todo el mundo modificando el encabezado, lo cual es una paradoja en lo que a mí respecta: si cambio la implementación de mi código (la parte CPP), luego la interfaz (la parte HPP) NO debe cambiar. Citando a Leonidas: "¡ Esto es ENCAPSULACIÓN! "

Editar 2014-09-20

¿Cuándo son realmente mejores las clases los métodos estáticos que los espacios de nombres con funciones que no son miembros?

Cuando necesite agrupar funciones y alimentar ese grupo a una plantilla:

namespace alpha { void foo() ; void bar() ; } struct Beta { static void foo() ; static void bar() ; }; template <typename T> struct Gamma { void foobar() { T::foo() ; T::bar() ; } }; Gamma<alpha> ga ; // compilation error Gamma<Beta> gb ; // ok gb.foobar() ; // ok !!!

Porque, si una clase puede ser un parámetro de plantilla, un espacio de nombres no puede.


En C ++ desea crear una función estática de una clase (no una clase estática).

class BitParser { public: ... static ... getBitAt(...) { } };

Entonces deberías poder llamar a la función usando BitParser :: getBitAt () sin crear una instancia de un objeto que supongo que es el resultado deseado.


En Managed C ++, la sintaxis de clase estática es: -

public ref class BitParser abstract sealed { public: static bool GetBitAt(...) { ... } }

... mejor tarde que nunca...


Esto es similar a la forma en que C # lo hace en C ++

En C # file.cs puedes tener una variable privada dentro de una función pública. Cuando esté en otro archivo, puede usarlo llamando al espacio de nombres con la función como en:

MyNamespace.Function(blah);

Aquí es cómo hacer lo mismo en C ++:

SharedModule.h

class TheDataToBeHidden { public: static int _var1; static int _var2; }; namespace SharedData { void SetError(const char *Message, const char *Title); void DisplayError(void); }

SharedModule.cpp

//Init the data (Link error if not done) int TheDataToBeHidden::_var1 = 0; int TheDataToBeHidden::_var2 = 0; //Implement the namespace namespace SharedData { void SetError(const char *Message, const char *Title) { //blah using TheDataToBeHidden::_var1, etc } void DisplayError(void) { //blah } }

OtroFile.h

#include "SharedModule.h"

OtroFile.cpp

//Call the functions using the hidden variables SharedData::SetError("Hello", "World"); SharedData::DisplayError();


Si está buscando una forma de aplicar la palabra clave "estática" a una clase, como puede hacerlo en C # por ejemplo, entonces no podrá usar C ++ administrado.

Pero la apariencia de su muestra, solo necesita crear un método estático público en su objeto BitParser. Al igual que:

BitParser.h

class BitParser { public: static bool getBitAt(int buffer, int bitIndex); // ...lots of great stuff private: // Disallow creating an instance of this object BitParser() {} };

BitParser.cpp

bool BitParser::getBitAt(int buffer, int bitIndex) { bool isBitSet = false; // .. determine if bit is set return isBitSet; }

Puede usar este código para llamar al método de la misma manera que su código de ejemplo.

¡Espero que ayude! Aclamaciones.


También puede crear una función libre en un espacio de nombres:

En BitParser.h

namespace BitParser { bool getBitAt(int buffer, int bitIndex); }

En BitParser.cpp

namespace BitParser { bool getBitAt(int buffer, int bitIndex) { //get the bit :) } }

En general, esta sería la forma preferida de escribir el código. Cuando no hay necesidad de un objeto, no use una clase.


Un caso en el que los espacios de nombres pueden no ser tan útiles para lograr "clases estáticas" es cuando se usan estas clases para lograr una composición sobre la herencia. Los espacios de nombres no pueden ser amigos de clases y, por lo tanto, no pueden acceder a miembros privados de una clase.

class Class { public: void foo() { Static::bar(*this); } private: int member{0}; friend class Static; }; class Static { public: template <typename T> static void bar(T& t) { t.member = 1; } };


Usted ''puede'' tener una clase estática en C ++, como se mencionó anteriormente, una clase estática es una que no tiene ningún objeto de la instancia. En C ++, esto se puede obtener declarando el constructor / destructor como privado. El resultado final es el mismo.


¿Puedo escribir algo como static class ?

No , según el proyecto de norma C ++ 11 N3337 Anexo C 7.1.1:

Cambio: en C ++, los especificadores estáticos o externos solo pueden aplicarse a nombres de objetos o funciones. Usar estos especificadores con declaraciones de tipo es ilegal en C ++. En C, estos especificadores se ignoran cuando se usan en declaraciones de tipo. Ejemplo:

static struct S { // valid C, invalid in C++ int i; };

Razón fundamental: los especificadores de la clase de almacenamiento no tienen ningún significado cuando se asocian con un tipo. En C ++, los miembros de la clase se pueden declarar con el especificador de clase de almacenamiento estático. Permitir que los especificadores de clase de almacenamiento en declaraciones de tipo podría hacer que el código sea confuso para los usuarios.

Y como struct , la class es también una declaración de tipo.

Lo mismo puede deducirse recorriendo el árbol de sintaxis en el Anexo A.

Es interesante notar que static struct era legal en C, pero no tuvo efecto: ¿Por qué y cuándo usar estructuras estáticas en la programación en C?