As variáveis estáticas da classe podem ser declaradas no cabeçalho, mas devem ser definidas em um arquivo .cpp. Isso ocorre porque pode haver apenas uma instância de uma variável estática e o compilador não pode decidir em qual arquivo de objeto gerado o colocará, portanto, você deve tomar a decisão.
Para manter a definição de um valor estático com a declaração em C ++ 11, uma estrutura estática aninhada pode ser usada. Nesse caso, o membro estático é uma estrutura e deve ser definido em um arquivo .cpp, mas os valores estão no cabeçalho.
class A
{
private:
static struct _Shapes {
const std::string RECTANGLE {"rectangle"};
const std::string CIRCLE {"circle"};
} shape;
};
Em vez de inicializar membros individuais, toda a estrutura estática é inicializada em .cpp:
A::_Shapes A::shape;
Os valores são acessados com
A::shape.RECTANGLE;
ou - como os membros são privados e devem ser usados apenas em A - com
shape.RECTANGLE;
Observe que essa solução ainda sofre com o problema da ordem de inicialização das variáveis estáticas. Quando um valor estático é usado para inicializar outra variável estática, a primeira ainda não pode ser inicializada.
// file.h
class File {
public:
static struct _Extensions {
const std::string h{ ".h" };
const std::string hpp{ ".hpp" };
const std::string c{ ".c" };
const std::string cpp{ ".cpp" };
} extension;
};
// file.cpp
File::_Extensions File::extension;
// module.cpp
static std::set<std::string> headers{ File::extension.h, File::extension.hpp };
Nesse caso, os cabeçalhos das variáveis estáticas conterão {""} ou {".h", ".hpp"}, dependendo da ordem de inicialização criada pelo vinculador.
Conforme mencionado por @ abyss.7, você também pode usar constexpr
se o valor da variável puder ser calculado em tempo de compilação. Mas se você declarar suas strings com static constexpr const char*
e seu programa usar de std::string
outra forma, haverá uma sobrecarga porque um novo std::string
objeto será criado toda vez que você usar essa constante:
class A {
public:
static constexpr const char* STRING = "some value";
};
void foo(const std::string& bar);
int main() {
foo(A::STRING); // a new std::string is constructed and destroyed.
}