Что именно означает "статический" при объявлении "глобальных" переменных в 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

  1. Запретить использование глобальной переменной вне области действия файла, который ее определяет.
  2. Разрешить локальным переменным внутри функции сохраняться при вызове функции, как в

    int getNextId() { static int id = 0; вернуть id ++; }

C++ наследует оба из них и добавляет два собственных использования.

  1. статические переменные-члены: переменные, которые являются "общими" во всех экземплярах класса, а также могут быть доступны без ссылки на экземпляр класса. Shared кажется неправильным словом, но, по сути, я считаю, что в результате любая ссылка на статическую переменную-член ссылается на одну и ту же область памяти.
  2. статические методы: методы, которые можно вызывать без ссылки на конкретный экземпляр класса, который его определяет.

Статический в основном означает, что переменная привязана к времени жизни программы, а не к какой-либо заданной функции или экземпляру класса. Когда вы должны использовать это? Не. Какова цель? Отладка данных, в основном.

Обычно в 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).

Другие вопросы по тегам