Последнее обновление:2026-10-13
C++ static: статические переменные и члены¶
Об авторе¶
Публичный аккаунт в WeChat:

При использовании с разными сущностями ключевое слово static имеет разный смысл. Мы можем использовать ключевое слово static:
Статические переменные: переменные в функции, переменные в классе
Статические члены класса: объекты класса и функции в классе
Теперь рассмотрим эти способы применения static подробнее:
Статические переменные
- Статические переменные в функции
Когда переменная объявлена как static, память под неё выделяется на всё время жизни программы. Даже если функция вызывается многократно, память под статическую переменную выделяется лишь один раз, а значение переменной из предыдущего вызова передаётся в следующий вызов функции. Это очень полезно в C / C++ и в любых других приложениях, где нужно сохранять предыдущее состояние функции.
#include <iostream>
#include <string>
using namespace std;
void demo()
{
// static variable
static int count = 0;
cout << count << " ";
// value is updated and
// will be carried to next
// function calls
count++;
}
int main()
{
for (int i=0; i<5; i++)
demo();
return 0;
}
Вывод:
В приведённой выше программе видно, что переменная count объявлена как static. Поэтому её значение передаётся от одного вызова функции к другому. При каждом вызове функции переменная count не инициализируется заново.
- Статические переменные в классе
Поскольку переменные, объявленные static, инициализируются только один раз — им выделяется память в отдельном статическом хранилище, — статические переменные в классе разделяются объектами. Для разных объектов не может существовать нескольких копий одной и той же статической переменной. Именно по этой причине статические переменные нельзя инициализировать с помощью конструктора.
#include<iostream>
using namespace std;
class Apple
{
public:
static int i;
Apple()
{
// Do nothing
};
};
int main()
{
Apple obj1;
Apple obj2;
obj1.i =2;
obj2.i = 3;
// prints value of i
cout << obj1.i<<" "<<obj2.i;
}
В приведённой выше программе видно, что мы попытались создать несколько копий статической переменной i для нескольких объектов. Но этого не произошло. Поэтому статическую переменную в классе пользователь должен явно инициализировать вне класса, используя имя класса и оператор разрешения области видимости, как показано ниже:
#include<iostream>
using namespace std;
class Apple
{
public:
static int i;
Apple()
{
// Do nothing
};
};
int Apple::i = 1;
int main()
{
Apple obj;
// prints value of i
cout << obj.i;
}
Вывод:
Статические члены
- Объекты класса как статические
Как и переменные, объекты, объявленные static, тоже имеют область видимости, которая длится до конца времени жизни программы.
Рассмотрим следующую программу, в которой объект не является статическим.
#include<iostream>
using namespace std;
class Apple
{
int i;
public:
Apple()
{
i = 0;
cout << "Inside Constructor\n";
}
~Apple()
{
cout << "Inside Destructor\n";
}
};
int main()
{
int x = 0;
if (x==0)
{
Apple obj;
}
cout << "End of main\n";
}
Вывод:
В приведённой выше программе объект объявлен нестатическим внутри блока if. Поэтому область видимости переменной ограничена блоком if. Следовательно, при создании объекта вызывается конструктор, а деструктор вызывается в тот момент, когда управление выходит за пределы блока if, потому что область видимости объекта ограничена блоком if, в котором он объявлен.
Если же объявить объект статическим, посмотрим, как изменится вывод.
#include<iostream>
using namespace std;
class Apple
{
int i;
public:
Apple()
{
i = 0;
cout << "Inside Constructor\n";
}
~Apple()
{
cout << "Inside Destructor\n";
}
};
int main()
{
int x = 0;
if (x==0)
{
static Apple obj;
}
cout << "End of main\n";
}
Вывод:
Вы явно видите изменение вывода. Теперь деструктор вызывается после завершения main. Это происходит потому, что область видимости статического объекта распространяется на всё время жизни программы.
- Статические функции в классе
Как и статические поля данных или статические переменные в классе, статические функции-члены не зависят от объектов класса. Нам разрешено вызывать статическую функцию-член через объект и '.', однако рекомендуется вызывать статические члены, используя имя класса и оператор разрешения области видимости.
Статическим функциям-членам разрешён доступ только к статическим полям данных или другим статическим функциям-членам; они не могут обращаться к нестатическим полям данных или функциям-членам класса.
#include<iostream>
using namespace std;
class Apple
{
public:
// static member function
static void printMsg()
{
cout<<"Welcome to Apple!";
}
};
// main function
int main()
{
// invoking a static member function
Apple::printMsg();
}
Вывод:
Ограничение области доступа
static также выполняет роль ограничения области доступа (аналогично анонимному пространству имён). Из issue: https://github.com/Light-City/CPlusPlusThings/issues/142
// source1.cpp
extern void sayHello();
const char* msg = "Hello World!\n";
int main()
{
sayHello();
return 0;
}
// source2.cpp
#include <cstdio>
extern char* msg;
void sayHello()
{
printf("%s", msg);
}
g++ нормально компилирует два приведённых выше файла и печатает Hello World!, но если добавить static к msg в source1.cpp, возникнет ошибка компиляции 'undefined reference to msg':
// source1.cpp
extern void sayHello();
static const char* msg = "Hello World!\n";
int main()
{
sayHello();
return 0;
}
Внутреннее связывание static (ограничение области доступа)¶
Благодарим issue #142 за замечание: когда static квалифицирует глобальную переменную или функцию, он также выполняет роль ограничения области доступа — меняет её связывание (linkage) с внешнего на внутреннее, что похоже по эффекту на анонимное пространство имён:
- Глобальная переменная без static: другие единицы трансляции могут получить к ней доступ через объявление
extern; - Статическая глобальная переменная/функция: видима только в текущей единице трансляции; даже объявление
externне сможет на неё сослаться (undefined reference).
В современном C++ для выражения «видно только в этом файле» рекомендуется использовать анонимное пространство имён (оно работает и для типов), однако понимать этот аспект static очень важно при чтении старого кода.
// file1.cpp
static int hidden = 42; // 内部链接:其他文件 extern 不可见
int visible = 1; // 外部链接:其他文件可 extern 访问
namespace { // 匿名命名空间:等价且更现代的写法
int also_hidden = 7;
}
Частые вопросы¶
Чем static-глобальная переменная отличается от обычной?¶
Внутренней компоновкой: static-глобальная видна только в своей единице трансляции. Обычная видна из других файлов и провоцирует конфликты имён.
Когда инициализируется static-локальная переменная?¶
Один раз, при первом проходе через определение; с C++11 — потокобезопасно. Живёт до конца программы.
Может ли static-метод обращаться к не-статическим полям?¶
Нет: у него нет this, доступны только статические члены.
Похожие темы¶
- C++ чисто виртуальные функции и абстрактные классы | C++那些事
- C++ утверждения assert | C++那些事
- C++ битовые поля | C++那些事
- Реализация полиморфизма C++ на языке C | C++那些事
- C++ const подробно: константы, указатель на const и const-указатель | C++那些事
- C++ всё семейство const | C++那些事
- C++ оператор разыменования * | C++那些事
- C++ инициализация и присваивание | C++那些事
- C++ возврат нескольких значений | C++那些事
- C++ ключевое слово mutable | C++那些事