¿Qué significa tener una referencia indefinida a un miembro estático?

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?

(Nota: Esto debe ser una entrada a las preguntas frecuentes de C ++ de Stack Overflow . Si desea criticar la idea de proporcionar una pregunta frecuente en este formulario, entonces la publicación en meta que inició todo esto sería el lugar para hacerlo). esa pregunta se monitorea en la sala de chat de C ++ , donde la idea de las preguntas frecuentes comenzó en primer lugar, por lo que es muy probable que su respuesta sea leída por aquellos a quienes se les ocurrió la idea).

Para comprender esto, debe tener una buena comprensión de la comstackción y el enlace , y las diferencias entre las declaraciones y las definiciones .


Considera la siguiente clase:

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

Aquí, exampleStaticMember está declarado pero no definido. Esto significa que si exampleStaticMember se usa de una manera que significa que debe tener una dirección, entonces debe haber una definición separada para él. En general, ninguna statement de un miembro de datos estáticos en una definición de clase es una definición de ese miembro.

La statement 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 generalmente se ve así:

 //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 se debe poner en el encabezado con la clase, porque eso podría romper la regla de una sola definición .

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

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

En este caso, todavía se requiere la definición en el archivo cpp, pero no está permitido tener un inicializador:

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

Los miembros estáticos que se han inicializado así se pueden usar en expresiones constantes.

Plantillas

Para un miembro de datos estáticos de una plantilla, las cosas son ligeramente diferentes. El miembro estático debe definirse en el encabezado junto con el rest de la clase:

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

Esto funciona porque hay una excepción específica a la regla de una definición para los miembros de datos estáticos de las plantillas de clases.

Otros usos de la estática

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

Cuando se aplica a objetos en un scope 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 enlaces internos . Este uso está en desuso para los objetos, ya que el espacio de nombre sin nombre brinda una mejor alternativa.

Debe crear instancias de 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;