2011-08-06 18 views
7

tengo una cabecera llamada filepaths.h que define una serie de variables estáticas:¿Por qué variables estáticas necesitan ser declarados dos veces en C++

#ifndef FILEPATHS_H 
#define FILEPATHS_H 

class FilePaths { 

public: 

    static QString dataFolder(); 
    static QString profileFolder(); 

private: 

    static QString dataFolder_; 
    static QString profileFolder_; 

}; 

} 
#endif // FILEPATHS_H 

Y un he asociado filepaths.cpp cuales al principio parecía como esto:

#include "FilePaths.h" 

QString FilePaths::dataFolder() { 
    return dataFolder_; 
} 

QString FilePaths::profileFolder() { 
    return profileFolder_; 
} 

sin embargo que no funcionaron - tengo un "error de símbolo no resuelto" error de vinculador sobre todas las variables estáticas. Así que he añadido estas variables en el archivo de C++ de esta manera:

#include "FilePaths.h" 

QString FilePaths::dataFolder_ = ""; 
QString FilePaths::profileFolder_ = ""; 

QString FilePaths::dataFolder() { 
    return dataFolder_; 
} 

QString FilePaths::profileFolder() { 
    return profileFolder_; 
} 

y esto funciona, sin embargo, no entiendo por qué.

¿Por qué estas variables estáticas deben definirse dos veces? ¿O tal vez no los estoy definiendo sino inicializándolos? Pero aún así, ¿por qué tiene que hacerse? ¿O debería escribir mi clase de manera diferente?

Respuesta

8

Una es una definición, la otra es una declaración. La diferencia es que las declaraciones pueden aparecer varias veces, y para las variables que no están en una clase, tal vez nunca, mientras que las definiciones pueden aparecer una y solo una vez.

Las razones para necesitar declaraciones y definiciones separadas es la historia arcaica, el tipo de cosas donde básicamente no tiene que ser así, pero es así para que C++ sea compatible con C, que fue diseñado para compilarse en la década de 1970.

+3

No creo que sea tan arcaico. Las declaraciones dicen que "existe en algún lugar una variable/clase/función llamada X", mientras que las definiciones dicen "X reside aquí, el compilador asigna almacenamiento para ello".La capacidad de separar declaraciones y definiciones es lo que permite múltiples unidades de traducción en un lenguaje de tipo estático sin que el compilador tenga que ser demasiado inteligente y adivinar sus intenciones. – vsekhar

+0

No es realmente arcaico, ya que ambos estándares son (incluso ahora, C99/C++ 11) muy imprecisos en el proceso del enlazador real, y la definición en un determinado archivo cpp dará como resultado una definición en el archivo de objeto resultante, si esto no era el caso, el vinculador no encontraría una referencia única al vincular todos los códigos. – rubenvb

+0

vsekhar, @rubenvb: Me gustaría señalar que para el código de plantilla, obtenemos múltiples definiciones (en archivos de objeto) de funciones y atributos estáticos, pero el vinculador las maneja bien. –

2

De http://weblogs.asp.net/whaggard/archive/2004/11/05/252685.aspx:

tiene que declarar fuera de la clase, porque de lo contrario el compilador no sabe qué unidad de traducción (por lo tanto objeto de archivo) del miembro se supone que debe ir.

Porque, como dijo DeadMG, puede declarar una variable muchas veces pero definirla solo una vez. Creo que es como prototipos de funciones: puedes tener tantos como quieras, pero solo uno puede ir con un cuerpo y definir la función.

0

No las declara dos veces, la declaración ocurre en el encabezado de la clase y la definición, el punto donde la variable está realmente allí y asignará algo de memoria, está en la parte .cpp.

Pero la diferencia con una variable de instancia común está allí, la parte estática solo está allí una vez por clase para cualquier instancia que cree.

0

Esto se debe a que, cuando declaras una clase, estás declarando una estructura para las instancias específicas de esa clase, PERO en caso de variables estáticas en una clase, son las que se pueden inicializar antes que cualquier objeto de la clase es creado. VEA que no hay espacio reservado cuando declaramos una clase en la memoria, pero el espacio está reservado cuando declaramos el objeto de la clase. El miembro NO de la clase se puede iniciar como int a = 2; pero esto se puede hacer como 'static int a = 2;' es posible en el espacio de reserva de declaración de clase para ellos en la segunda declaración, & debe ser consciente de ello

Cuestiones relacionadas