Статичні змінні класу можуть бути оголошені у заголовку, але повинні бути визначені у файлі .cpp. Це тому, що може бути лише один екземпляр статичної змінної, і компілятор не може вирішити, в який згенерований об’єктний файл його поставити, тож вам доведеться приймати рішення.
Для збереження визначення статичного значення з оголошенням у C ++ 11 може бути використана вкладена статична структура. У цьому випадку статичний член є структурою і повинен бути визначений у файлі .cpp, але значення знаходяться в заголовку.
class A
{
private:
static struct _Shapes {
const std::string RECTANGLE {"rectangle"};
const std::string CIRCLE {"circle"};
} shape;
};
Замість ініціалізації окремих членів вся статична структура ініціалізується у .cpp:
A::_Shapes A::shape;
Доступ до значень здійснюється за допомогою
A::shape.RECTANGLE;
або - оскільки члени приватні і мають на увазі використовуватись лише від A - с
shape.RECTANGLE;
Зауважимо, що це рішення все ще страждає від проблеми порядку ініціалізації статичних змінних. Коли статичне значення використовується для ініціалізації іншої статичної змінної, перша може ще не ініціалізуватися.
// 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 };
У цьому випадку статичні змінні заголовки будуть містити або {""}, або {".h", ".hpp"}, залежно від порядку ініціалізації, створеного лінкером.
Як зазначає @ abyss.7, ви також можете використовувати, constexpr
якщо значення змінної можна обчислити під час компіляції. Але якщо ви оголосите свої рядки static constexpr const char*
і ваша програма використовує в std::string
іншому випадку, буде накладні витрати, оскільки новий std::string
об’єкт буде створюватися кожен раз, коли ви використовуєте таку константу:
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.
}