2011-08-17 32 views
18

Acabo de escribir una clase con algunos miembros de datos estáticos, pero ahora recibo errores sobre "referencias indefinidas". ¿Por qué esto no funciona? ¿Qué estoy haciendo mal?¿Qué significa tener una referencia indefinida a un miembro estático?

(Nota:.. Esto está destinado a ser una entrada a Stack Overflow's C++ FAQ Si desea realizar una crítica de la idea de ofrecer un FAQ en esta forma, a continuación, the posting on meta that started all this sería el lugar para hacer que las respuestas a esta pregunta son monitoreado en el C++ chatroom, donde la idea FAQ se inició en el primer lugar, por lo que su respuesta es muy probable que se lee por los que se le ocurrió la idea.)

+0

http://www.parashift.com/c++faq-lite/ctors.html#faq-10.12 – PlasmaHH

Respuesta

26

Para entender esto, usted debe tener una buena comprensión de compiling and linking, y las diferencias entre declarations and definitions.


Considérese la clase siguiente:

//In header file 
class Example { 
    static bool exampleStaticMember; 
}; 

Aquí, exampleStaticMember se declara pero no se define. Esto significa que si exampleStaticMember se utiliza de una manera que significa que debe tener una dirección, entonces debe haber una definición separada para ella. En general, ninguna declaración de un miembro de datos estáticos en una definición de clase es una definición de ese miembro.

La declaración requerida generalmente se coloca en el archivo cpp que contiene las otras definiciones para los miembros de la clase. Debe estar en el mismo espacio de nombres que la definición de clase. La definición se ve típicamente como:

//In source file: 
//This may optionally have an initialiser (eg "= true") 
bool Example::exampleStaticMember; 

la definición se puede poner en cualquier archivo cpp, pero no debe ser puesto en la cabecera de la clase, porque eso sería probable que se rompa el One Definition Rule.

Como caso especial, si la variable miembro estática es un tipo integral o de enumeración const entonces puede tener un inicializador en la definición de clase:

//In header file 
class Example { 
    static const int initialised = 15; 
}; 

En este caso, la definición en el archivo CPP es siendo necesaria, pero no se le permite tener un inicializador: miembros

//In source file 
//Note: no initialiser! 
const int Example::initialised; 

estáticas que han sido inicializados como esto se pueden utilizar en expresiones constantes.

plantillas

Para un miembro de datos estáticos de una plantilla, las cosas son un poco diferentes. El miembro estático se debe definir en la cabecera junto con el resto de la clase:

//In header file 
template<typename T> 
class Example { 
    static int exampleInt; 
    static T exampleT; 
} 
template<typename T> int Example<T>::exampleInt; 
template<typename T> T Example<T>::exampleT; 

Esto funciona porque hay una excepción específica a la Regla de una definición de los miembros de datos estáticos de plantillas de clase.

Otros usos de estática

cuando se aplica la palabra clave static a las funciones y objetos que no están en un ámbito de clase puede tener un significado muy diferente.

Cuando se aplica a objetos en un alcance de función, declara un objeto que se inicializa en la primera ejecución de la función y que posteriormente conserva su valor entre llamadas de función.

Cuando se aplica a objetos o funciones en el ámbito del espacio de nombres (fuera de cualquier definición de clase o función), declara objetos o funciones con internal linkage. Este uso está en desuso para los objetos, ya que el unnamed-namespace proporciona una mejor alternativa.

+0

"Como un caso especial, si la variable de miembro estática es un tipo de enumeración integral o de enumeración, entonces puede tener un inicializador en la definición de clase ". ¿Te refieres a la declaración * de clase * aquí? –

+0

@SamGoldberg: No, si hubiera dicho _declaration_, me referiría a una declaración directa (por ejemplo, 'class Example;'). Por _definition_, me refiero al código que declara a los miembros de la clase. (Sí, estos miembros pueden definirse ellos mismos fuera de la definición de la clase, pero eso no es importante aquí). – Mankarse

5

hay que crear instancias de los miembros estáticos definidos en un encabezado en un archivo .cpp. Por ejemplo:

// foo.h 

class foo { 
    static int X; 
}; 


// foo.cpp 

#include "foo.h" 

int foo::X = 0; 
Cuestiones relacionadas