Pregunta

¿Cómo crear una clase estática en C++?Yo debería ser capaz de hacer algo como:

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

Suponiendo que yo crea el BitParser clase.¿Qué sería de la BitParser definición de la clase parece?

¿Fue útil?

Solución

Si usted está buscando una manera de aplicar la "estática" de la palabra clave a una clase, como usted puede en C# por ejemplo, entonces usted no podrá, sin el uso de C++Administrado.

Pero el aspecto de la muestra, usted sólo tiene que crear un método estático público en su BitParser objeto.Así:

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;
}

Usted puede utilizar este código para llamar al método de la misma manera como su código de ejemplo.

Espero que ayude!Saludos.

Otros consejos

Considere la posibilidad de Matt Precio de la solución.

  1. En C++, una "clase estática" no tiene ningún significado.Lo más cercano es una clase sólo con métodos estáticos y los miembros.
  2. El uso de métodos estáticos se limite sólo a usted.

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

Editar 2011-11-11

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

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

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

Pero usted debe recordar que "las clases estáticas" son hacks en Java-como la clase de idiomas (por ejemplo,C#) que son incapaces de tener no-miembro de funciones, por lo que tienen en lugar de moverse dentro de las clases como de los métodos estáticos.

En C++, lo que realmente desea es un no-miembro de la función que se va a declarar en un espacio de nombres:

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

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

¿Por qué es eso?

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

  • métodos estáticos tienen acceso a las clases privadas símbolos
  • privado de los métodos estáticos son todavía visibles (si inaccesibles) a todo el mundo, lo cual transgrede un poco la encapsulación
  • los métodos estáticos no pueden ser hacia adelante-declaró
  • los métodos estáticos no puede ser sobrecargado por la clase de usuario sin necesidad de modificar el encabezado de la biblioteca
  • no hay nada que pueda ser hecho por un método estático que no se puede hacer mejor que un (posiblemente amigo) no-miembros de la función en el mismo espacio de nombres
  • los espacios de nombres tiene su propia semántica (que pueden ser combinadas, pueden ser anónimos, etc.)
  • etc.

Conclusión:No copiar/pegar que Java/C#'s patrón en C++.En Java/C#, el patrón es obligatorio.Pero en C++, es mal estilo.

Editar 2010-06-10

No era un argumento a favor para el método estático porque a veces, uno necesita usar un estático variable miembro privada.

No estoy de acuerdo en algo, como se muestra a continuación:

La "Estática miembro privado" solución

// HPP

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

En primer lugar, myGlobal se llama myGlobal porque es todavía un global de la variable privada.Un vistazo a la CPP fuente de 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 libre barC no pueden acceder a Foo::myGlobal parece una buena cosa, desde un punto de vista de la encapsulación de la...Es genial porque alguien que busca en la HPP no podrá (a menos de recurrir al sabotaje) para acceder a Foo::myGlobal.

Pero si usted mira de cerca, usted encontrará que es un error colosal:No sólo su variable privada aún debe ser declarado en la HPP (y por lo tanto, visible para todo el mundo, a pesar de ser privada), pero usted debe declarar en la misma HPP todos (como en TODAS) las funciones que serán autorizados para acceder a ella !!!

Así el uso de un privado miembro estático, es como caminar en el exterior en el desnudo con la lista de sus amantes tatuado en tu piel :Nadie está autorizado a tocar, pero todo el mundo es capaz de echar un vistazo a.Y el bono:Todo el mundo puede tener los nombres de las personas autorizadas para jugar con sus copartícipes.

private de hecho...:-D

Anónimo "espacios de nombres" solución

Anónimo espacios de nombres se tiene la ventaja de hacer las cosas en privado realmente privado.

En primer lugar, la CH encabezado

// HPP

namespace Foo
{
   void barA() ;
}

Sólo para estar seguro de que usted comentó:No es inútil declaración de barB ni myGlobal.Lo que significa que no hay una lectura de la cabecera sabe lo que se esconde detrás de barA.

A continuación, 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 se puede ver, como la llamada "clase estática" de la declaración, fooA y fooB todavía son capaces de acceder a myGlobal.Pero nadie más puede.Y a nadie más, fuera de este CPP sabe fooB y myGlobal siquiera existen!

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

¿Realmente importa?

A menos que los usuarios de su código son saboteadores (voy a dejar que usted, como un ejercicio, encontrar cómo se puede acceder a la parte privada de una clase pública mediante un sucio comportamiento indefinido hack...), lo que private es private, incluso si es visible en el private sección de una clase declarada en un encabezado.

Aún así, si usted necesita añadir otra "función privada" con el acceso a la privada en miembro, usted todavía debe declarar a todo el mundo mediante la modificación de la cabecera, que es una paradoja ya que a mí respecta: Si yo cambio la aplicación de mi código (el CPP parte), entonces el interfaz (la CH parte) NO debe cambiar. Citando A Leonidas :"Este es el ENCAPSULAMIENTO!"

Editar 2014-09-20

Cuando son las clases de los métodos estáticos son de hecho mejores que los espacios de nombres que no son miembros de las funciones?

Cuando usted necesita para agrupar funciones y alimentar a 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, una de los espacios de nombres no.

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 para escribir el código.Cuando no hay ninguna necesidad de que un objeto no utilice una clase.

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

las clases estáticas son sólo el compilador de la mano que sostiene a usted y a dejar de escribir cualquier instancia de métodos y variables.

Si usted acaba de escribir una clase normal sin ningún tipo de métodos de instancia y de variables, es la misma cosa, y esto es lo que te gustaría hacer en C++

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

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

A continuación, usted debe ser capaz de llamar a la función utilizando BitParser::getBitAt() sin crear instancias de un objeto que supongo que es el resultado deseado.

Puedo escribir algo como static class?

No, de acuerdo a la C++11 N3337 borrador de estándar Anexo C 7.1.1:

Cambio:En C ++, la estática o extern especificadores sólo puede ser aplicado a nombres de objetos o funciones.El uso de estos especificadores de tipo de declaraciones es ilegal en C ++.En C, estos especificadores son ignorados cuando se utiliza en tipo de declaraciones.Ejemplo:

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

Justificación:Los especificadores de clase de almacenamiento no tiene ningún significado cuando se asocia con un tipo.En C ++, clase los miembros pueden ser declarados con la estática de especificador de clase de almacenamiento.Permitiendo a los especificadores de clase de almacenamiento tipo declaraciones podrían representar el código confuso para los usuarios.

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

El mismo puede ser deducido, al caminar por el árbol de sintaxis en el Anexo A.

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

'Puede' tener una clase estática en C++, como se mencionó antes, una clase estática es uno que no tiene ningún objeto de crear instancias de ella.En C++, este puede ser obtenido por declarar el constructor/destructor como privado.El resultado final es el mismo.

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

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

...mejor tarde que nunca...

Esto es similar a la de C#'s la forma de hacerlo en C++

En el archivo de C#.cs puede tener private var dentro de una función pública.Cuando en otro archivo que se puede utilizar mediante una llamada al espacio de nombres con la función como en:

MyNamespace.Function(blah);

He aquí cómo imp el 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
  }
}

OtherFile.h

#include "SharedModule.h"

OtherFile.cpp

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

A diferencia de otros administrados lenguaje de programación, "estático de la clase" no tiene NINGÚN significado en C++.Usted puede hacer uso de la función miembro estática.

Como se ha señalado aquí, una mejor manera de lograr esto en C++ puede ser el uso de espacios de nombres.Pero dado que nadie ha mencionado el final la palabra clave aquí, voy a postear lo que es un equivalente directo de static class desde C# se vería 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
}

Uno de los casos donde los espacios de nombres pueden no ser tan útil para el logro de "las clases estáticas" es cuando el uso de estas clases para lograr la composición a lo largo de la herencia.Los espacios de nombres no pueden ser amigos de las clases y por lo tanto no puede acceder a los 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;
  }
};
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top