Что именно означает "статический" при объявлении "глобальных" переменных в C++?
Это расширение сферы моего предыдущего вопроса.
Что такое "статический", как он используется и какова цель использования "статического" при работе с C++?
Благодарю.
6 ответов
Ключевое слово static
имеет разные значения в C++, в зависимости от контекста.
Когда объявляется свободная функция или глобальная переменная, это означает, что функция не должна быть доступна вне этой единственной единицы перевода:
// test.cpp
static int a = 1;
static void foo() {}
Если результат компиляции этой единицы перевода связан с другой единицей перевода, содержащей символы a
а также foo
оно не нарушит единого правила определения, как в данном конкретном переводческом модуле a
а также foo
являются частными символами. Это использование было отменено безымянными пространствами имен.
// test2.cpp
namespace {
static int a = 1;
static void foo() {}
}
Когда объявляется локальная переменная внутри функции, это означает, что время жизни переменной будет продолжаться от первого вызова функции до конца программы, а не только на время вызова:
int foo() {
static int counter = 0;
return ++counter;
}
int main() {
for ( int i = 0; i < 10; ++i ) {
std::cout << foo() << std::endl;
}
}
В предыдущем коде counter
инициализируется один раз, когда foo
вызывается в первый раз, но переменная переживет функцию и сохранит значение в различных вызовах функций. В предыдущем коде будет напечатано "1 2 3 4... 10". Если переменная не была объявлена static
тогда вывод будет "1 1 1... 1".
В рамках класса, static
означает, что член является членом класса, а не конкретного экземпляра. Это использование эквивалентно использованию в вашем другом вопросе: использование этого конкретного члена не связано с каким-либо конкретным объектом.
struct test {
int x;
static int y;
};
int test::y; // need to define it in one translation unit
int main() {
// test::x = 5; // !error cannot access a non-static member variable
// without an instance
test::y = 5; // ok
test t, other;
t.x = 10; // ok
t.y = 15; // ok, the standard allows calling a static member through
// an instance, but this is the same as test::y
}
В этом случае член x
является нестатическим атрибутом члена, и поэтому x
для каждого экземпляра класса. В примере программы t.x
а также other.x
ссылаются на разные целые числа. С другой стороны y
является static
и, таким образом, существует единственный случай test::y
в программе. Даже если стандарт позволяет звонить t.y
а также other.y
оба использования относятся к одной и той же переменной. То же самое касается методов членов. Если они являются статическими, они являются методами уровня класса и могут быть вызваны без экземпляра, а если они нестатические, они применяются к конкретному экземпляру и a.b
или же a->b
синтаксис должен быть использован.
Это использование static
аналогично использованию одного и того же ключевого слова в Java, в то время как два других не представлены на этом языке. Существует одно использование ключевого слова в Java, которого нет в C++, и это использование статических инициализаторов классов (блок кода на уровне класса, окруженный static { ... }
). В Java этот блок кода будет выполняться при загрузке класса и только один раз. Инициализация статических переменных-членов в C++ должна выполняться в инициализаторе определения переменной.
Это означает, что переменная является локальной для единицы перевода (проще говоря, для одного исходного файла) и недоступна извне. Такое использование статического кода фактически не рекомендуется в текущем стандарте C++ - вместо этого вы должны использовать анонимные пространства имен:
static int x = 0;
должно быть:
namespace {
int x = 0;
}
Этот материал, кажется, довольно хорошо освещен здесь.
Но, перефразируя, есть 2 использования в C
- Запретить использование глобальной переменной вне области действия файла, который ее определяет.
Разрешить локальным переменным внутри функции сохраняться при вызове функции, как в
int getNextId() { static int id = 0; вернуть id ++; }
C++ наследует оба из них и добавляет два собственных использования.
- статические переменные-члены: переменные, которые являются "общими" во всех экземплярах класса, а также могут быть доступны без ссылки на экземпляр класса. Shared кажется неправильным словом, но, по сути, я считаю, что в результате любая ссылка на статическую переменную-член ссылается на одну и ту же область памяти.
- статические методы: методы, которые можно вызывать без ссылки на конкретный экземпляр класса, который его определяет.
Статический в основном означает, что переменная привязана к времени жизни программы, а не к какой-либо заданной функции или экземпляру класса. Когда вы должны использовать это? Не. Какова цель? Отладка данных, в основном.
Обычно в C++, если вы обнаружите, что используете статические данные, вы сделали это неправильно. Есть моменты, когда это уместно, но они очень редки.
Когда static используется в классе в C++, это означает более или менее то же самое, что и в Java. Для переменных это означает, что один экземпляр переменной существует для всех классов и для функций, это означает, что функция вообще не имеет неявного доступа к этому указателю.
В C и C++, когда static используется для глобальной переменной или функции, это означает, что на переменную можно ссылаться только в текущем файле C или C++. Другими словами, компилятор не должен генерировать какие-либо символы перемещения для переменной или функции.
Когда static используется рядом с переменной в локальной функции, это означает, что переменная не выходит из области видимости, но сохраняет свое значение от вызова функции до вызова функции. Переменная становится эффективной глобальной переменной, доступ к которой возможен только из данной функции.
Статические члены класса - это данные и функции, которые связаны с самим классом, а не с объектами класса.
В следующем примере класс Fred имеет статический элемент данных x_ и экземплярный элемент данных y_. Существует только одна копия Fred::x_ независимо от того, сколько объектов Fred создано (включая объекты Fred), но существует один y_ на объект Fred. Таким образом, говорят, что x_ ассоциируется с классом, а y_ ассоциируется с отдельным объектом класса. Точно так же класс Fred имеет статическую функцию-член f() и экземплярную функцию-член g ().
class Fred {
public:
static void f() throw(); <-- 1
void g() throw(); <-- 2
protected:
static int x_; <-- 3
int y_; <-- 4
};
(1) Функция-член, связанная с классом
(2) Функция-член, связанная с отдельным объектом класса
(3) Член данных, связанный с классом
(4) Член данных, связанный с отдельным объектом класса
Использование:
Если вы хотите сохранить количество экземпляров созданного класса, вы используете статическую переменную. Например, в классе "Автомобиль" каждый экземпляр автомобиля может иметь уникальный серийный номер (в данном случае _y), и компания может захотеть отслеживать количество произведенных автомобилей (в данном случае _x).