2011-02-16 33 views
52

He notado que algunas de mis funciones en una clase en realidad no están accediendo al objeto, así que las hice static. Luego, el compilador me dijo que todas las variables a las que acceden también deben ser estáticas, bueno, bastante comprensibles hasta ahora. Tengo un montón de variables de cadena comoC++ inicializa variables estáticas en clase?

string RE_ANY = "([^\\n]*)"; 
string RE_ANY_RELUCTANT = "([^\\n]*?)"; 

y así sucesivamente en la clase. Los hice todos static const porque nunca cambian. Sin embargo, mi programa solo se compila si los saco de la clase: de lo contrario, MSVC++ 2010 se queja de que "solo se pueden inicializar variables integrales constantes estáticas dentro de una clase".

Bueno, eso es desafortunado. ¿Hay alguna solución? Me gustaría dejarlos dentro de la clase a la que pertenecen.

Respuesta

93

No pueden ser inicializadas dentro de la clase, pero se pueden inicializar fuera de la clase, en un archivo de origen:

// inside the class 
class Thing { 
    static string RE_ANY; 
    static string RE_ANY_RELUCTANT; 
}; 

// in the source file 
string Thing::RE_ANY = "([^\\n]*)"; 
string Thing::RE_ANY_RELUCTANT = "([^\\n]*?)"; 

actualización

he acabo de dar cuenta de la primera línea de su pregunta - usted no desea hacer esas funciones static, desea hacerlas const. Hacerlos static significa que ya no están asociados con un objeto (por lo que no pueden acceder a ningún miembro no estático), y hacer que los datos sean estáticos significa que se compartirán con todos los objetos de este tipo. Esto bien puede no ser lo que quieres. Hacerlos const simplemente significa que no pueden modificar ningún miembro, pero que aún pueden acceder a ellos.

+1

ellos no tienen acceso a nada en el objeto, argumentos de referencia Por lo tanto, probablemente deberían ser tanto 'const' como' static'. –

+7

@Felix: no es posible, 'const' significa que no modifica' this' ... y no hay 'this' para los métodos' static'. –

+0

@Matthieu: Muy buena explicación. Entonces 'estático' es el correcto. –

15

Las variables de miembros estáticos deben declararse en la clase y luego definirse fuera de ella.

No hay solución, solo ponga su definición real en un archivo fuente.


Desde su descripción huele a que no está utilizando las variables estáticas de la manera correcta. Si nunca cambian, debe usar una variable constante, pero su descripción es demasiado genérica para decir algo más.

Las variables de miembro estático siempre tienen el mismo valor para cualquier instancia de su clase: si cambia una variable estática de un objeto, también cambiará para todos los demás objetos (y de hecho también puede acceder a ellos sin una instancia) de la clase - es decir: un objeto).

+1

Ellos son const ahora - que sólo tiene que ser estática, así para que pueda usarlos en métodos estáticos. ¿Cuál es el motivo de esa regla que deben declararse dentro y definidos fuera de una clase? Eso no tiene mucho sentido para mí. –

+1

@Felix Dombek: Creo que el motivo es que la clase es (/ podría) declarada para cada archivo de origen que compila y vincula, pero las variables reales deben definirse solo una vez. Esa es la misma razón por la que necesita declarar explícitamente como 'extern' las variables definidas en otros archivos fuente. – peoro

+1

@ peoro: ¡Eso parece razonable! Pero entonces, ¿por qué está permitido para los tipos de datos integrales? Eso tampoco debería estar permitido, entonces ... –

9

Creo que vale la pena agregar que una variable estática no es lo mismo que una variable constante.

usando una variable constante en una clase

struct Foo{ 
    const int a; 
    Foo(int b) : a(b){} 
} 

y nos declarará como al igual que

fooA = new Foo(5); 
fooB = new Foo(10); 
// fooA.a = 5; 
// fooB.a = 10; 

Para una variable estática

que se utiliza como tal

barA = new Bar(5); 
barB = new Bar(10); 
// barA.a = 10; 
// barB.a = 10; 
// Bar::a = 10; 

Ya ve lo que sucede aquí.La variable constante, que se instancia junto con cada instancia de Foo, como instancia de Foo tiene un valor separado para cada instancia de Foo, y Foo no puede cambiarla en absoluto.

Donde con Bar, su valor es solo uno para Bar :: a no importa cuántas instancias de Bar se realicen. Todos comparten este valor, también puedes acceder a él con sus instancias de Bar. La variable estática también cumple las reglas para público/privado, por lo que podría hacer que solo las instancias de Bar puedan leer el valor de Bar :: a;

+0

huh ... lo encuentro gracioso nadie ha señalado mi terrible uso innecesario de 'nuevo'. No es realmente motivo de preocupación para esta pregunta, pero sí, evite usar 'nuevo' cuando no lo necesite, y nunca más lo hará. – thecoshman

24

Mike Seymour le ha dado la respuesta correcta, pero para agregar ...
C++ permite declarar y definir en su cuerpo de la clase sólo static const tipos integrales, como dice el compilador. Así que en realidad se puede hacer:

class Foo 
{ 
    static const int someInt = 1; 
    static const short someShort = 2; 
    // etc. 
}; 

Y no se puede hacer eso con cualquier otro tipo, en los casos que se deben definir en el archivo .cpp.

10

Desde C++ 11 se puede hacer dentro de una clase con constexpr.

class stat { 
    public: 
     // init inside class 
     static constexpr double inlineStaticVar = 22; 
}; 

La variable se puede acceder ahora con:

stat::inlineStaticVar 
+0

Definitivamente bueno para ints, double, punteros, etc. Sin embargo, esto no funciona con la cadena de la pregunta, ya que la cadena no es literal o de referencia. –

+0

Buen punto. Sin embargo, podría hacer 'constexpr char RE_ANY [] =" ([^ \\ n] *) ";' o 'constexpr std :: string_view RE_ANY (" ([^ \\ n] *) ", 9);' . – 0ax1

2

Si su objetivo es inicializar la variable estática en el archivo de cabecera (en lugar de un archivo * .cpp, que es posible que desee si se apegan a un modismo de "solo encabezado"), entonces puede evitar el problema de inicialización mediante el uso de una plantilla. Las variables estáticas templadas se pueden inicializar en un encabezado, sin causar que se definan múltiples símbolos.

Vea aquí un ejemplo:

Static member initialization in a class template

1

Opcionalmente, se mueven todas sus constantes al archivo .cpp sin declaración en el archivo .h. Use el espacio de nombres anónimo para hacerlos invisibles más allá del módulo cpp.

// MyClass.cpp 

#include "MyClass.h" 

// anonymous namespace 
namespace 
{ 
    string RE_ANY = "([^\\n]*)"; 
    string RE_ANY_RELUCTANT = "([^\\n]*?)"; 
} 

// member function (static or not) 
bool MyClass::foo() 
{ 
    // logic that uses constants 
    return RE_ANY_RELUCTANT.size() > 0; 
} 
5

Solo para agregar el resto de las demás respuestas. Para inicializar un miembro estático complejo , puede hacerlo de la siguiente manera:

Declarar su miembro estático como de costumbre.

// myClass.h 
class myClass 
{ 
static complexClass s_complex; 
//... 
}; 

Haga una pequeña función para inicializar su clase si no es trivial hacerlo. Esto se llamará solo la única vez que se inicializa el miembro estático. (Tenga en cuenta que se utilizará el constructor de copias de complexClass, por lo que debe estar bien definido).

//class.cpp  
#include myClass.h 
complexClass initFunction() 
{ 
    complexClass c; 
    c.add(...); 
    c.compute(...); 
    c.sort(...); 
    // Etc. 
    return c; 
} 

complexClass myClass::s_complex = initFunction(); 
Cuestiones relacionadas