245 votos

¿Cómo se crea una clase estática en C++?

¿Cómo se crea una clase estática en C++? Debería ser capaz de hacer algo como:

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

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

258voto

OJ. Puntos 16939

Si buscas una forma de aplicar la palabra clave "static" a una clase, como puedes hacer en C# por ejemplo, no podrás hacerlo sin usar Managed C++.

Pero por el aspecto de tu ejemplo, sólo necesitas crear un método estático público en tu objeto BitParser. Así:

// header file
class BitParser
{
public:
  static bool getBitAt(int buffer, int bitIndex);

  // .. lots of great stuff
};

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

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

Espero que esto ayude. Saludos.

238voto

paercebal Puntos 38526

Considere La solución de Matt Price .

  1. En C++, una "clase estática" no tiene ningún significado. Lo más parecido es una clase con sólo métodos y miembros estáticos.
  2. El uso de métodos estáticos sólo le limitará.

Lo que quieres es, expresado en la semántica de C++, poner tu función (para ello es una función) en un espacio de nombres.

Editar 2011-11-11

En C++ no existe una "clase estática". El concepto más cercano sería una clase con sólo métodos estáticos. Por ejemplo:

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

// source
void MyClass::myMethod()
{
   // etc.
}

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

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

// header
namespace MyNamespace
{
   static void myMethod() ;
}

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

¿Por qué?

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

  • los métodos estáticos tienen acceso a los símbolos privados de la clase
  • los métodos estáticos privados siguen siendo visibles (aunque inaccesibles) para todo el mundo, lo que rompe un poco la encapsulación
  • los métodos estáticos no pueden ser declarados hacia adelante
  • los métodos estáticos no pueden ser sobrecargados por el usuario de la clase sin modificar la cabecera de la biblioteca
  • no hay nada que pueda hacer un método estático que no pueda hacerse mejor que una función (posiblemente amiga) no miembro del 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 copies/pegues ese 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 un poco en desacuerdo, como se muestra a continuación:

La solución del "miembro privado estático"

// HPP

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

En primer lugar, myGlobal se llama myGlobal porque sigue siendo una variable privada global. Un vistazo al código fuente del CPP lo aclarará:

// 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 libre barC no pueda acceder a Foo::myGlobal parece algo bueno desde el punto de vista de la encapsulación... Es bueno porque alguien que mire la HPP no podrá (a menos que recurra al sabotaje) acceder a Foo::miGlobal.

Pero si lo miras con detenimiento, verás que es un error colosal: ¡¡¡No sólo tu variable privada debe ser declarada en la HPP (y por lo tanto, visible para todo el mundo, a pesar de ser privada), sino que debes declarar en la misma HPP todas (como en TODAS) las funciones que estarán autorizadas a acceder a ella !!!

Así que Utilizar un miembro estático privado es como salir a la calle desnudo con la lista de tus amantes tatuada en la piel: nadie está autorizado a tocar, pero todo el mundo puede echar un vistazo. Y el plus: todo el mundo puede tener los nombres de los autorizados a jugar con tus intimidades.

private en efecto... :-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.

En primer lugar, la cabecera HPP

// HPP

namespace Foo
{
   void barA() ;
}

Sólo para estar seguro de que remarcó: No hay ninguna declaración inútil de barB ni de myGlobal. Lo que significa que nadie que lea la cabecera 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 puedes ver, al igual que la declaración de la llamada "clase estática", fooA y fooB todavía pueden acceder a miGlobal. Pero nadie más puede. Y nadie más fuera de este CPP sabe que fooB y myGlobal existen.

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

¿Realmente importa?

A menos que los usuarios de tu código sean saboteadores (te dejaré, como ejercicio, encontrar cómo se puede acceder a la parte privada de una clase pública usando un sucio hack de comportamiento no definido...), lo que es private es private aunque sea visible en el private de una clase declarada en una cabecera.

Aun así, si necesitas añadir otra "función privada" con acceso al miembro privado, debes declararla a todo el mundo modificando la cabecera, lo cual es una paradoja en lo que a mí respecta: Si cambio la implementación de mi código (la parte CPP), entonces la interfaz (la parte HPP) NO debería cambiar. Citando a Leonidas : " ¡Esto es ENCAPSULACIÓN! "

62voto

Matt Price Puntos 9674

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 haya necesidad de un objeto no uses una clase.

12voto

Orion Edwards Puntos 54939

Si buscas una forma de aplicar la palabra clave "static" a una clase, como puedes hacer en C# por ejemplo

Las clases estáticas son sólo el compilador que te ayuda y te impide escribir cualquier método/variable de instancia.

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

11voto

Philip Reynolds Puntos 5118

En C++ quieres 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 instanciar un objeto, lo que supongo que es el resultado deseado.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X