Static: Многоцелевое ключевое слово

Большинство ключевых слов C++ позволяют сделать одну вещь. Вы используете int для объявления целочисленной переменной, или тогда, когда функция возвращает целое значение, или принимает целое число в качестве аргумента. Вы используете оператор new для выделения памяти, а оператор delete — для ее освобождения. Вы можете использовать const для указания, что значение переменной не может быть изменено. По иронии судьбы, ключевое слово static, хотя и означает «неизменный», имеет несколько (и, видимо, не связанных между собой) способов использования. Ключевое слово static может быть использовано в трех основных контекстах:

  • внутри функции;
  • внутри определения класса;
  • перед глобальной переменной внутри файла, составляющего многофайловую программу.

Использование static внутри функции является самым простым. Это просто означает, что после того, как переменная была инициализирована, она остается в памяти до конца программы. Вы можете думать об этом, как о переменной, которая хранит свое значение до полного завершения программы. Например, вы можете использовать статическую переменную для записи количества раз, когда функция была вызвана, просто добавив строки  static int count = 0; и count++; в функцию. Так как count является статической переменной, строка static int count = 0; будет выполняться только один раз. Всякий раз, когда функция вызывается, count будет иметь последнее значение, данное ему.

Вы также можете использовать static таким образом, чтобы предотвратить переинициализацию переменной внутри цикла. Например, в следующем коде переменная number_of_times будет равна 100, несмотря на то что строка static int number_of_times = 0; находится внутри цикла, где она, по-видимому, должна исполнятся каждый раз, когда программа доходит до цикла. Хитрость заключается в том, что ключевое слово static препятствует повторной инициализации переменной. Одной из особенностей использования ключевого слова static является то, что оно автоматически устанавливает переменную в ноль для вас — но не полагайтесь на это (это делает ваши намерения неясными).

for(int ix=0; ix < 10; ix++)
{
  for(int iy = 0; iy < 10; iy++)
  {
    static int number_of_times = 0;
    number_of_times++;
  }
}

Вы можете использовать статические переменные для сохранения информации о последнем значении возвращенной функции, например, если вы хотите сохранить максимальное значение, рассчитанное по функции. Если вы делаете разбор строки, вы можете также хранить последний знак, возвращенный функцией, для того, чтобы иметь возможность вызвать ее с аргументом, означающим, что она должна вернуть последний знак.

Второе использование static — внутри определения класса. Хотя большинство переменных, объявленных внутри класса могут иметь разное значение в каждом экземпляре класса, статические поля класса будут иметь то же значение для всех экземпляров данного класса и даже не обязательно создавать экземпляр этого класса. Полезно представить себе, что статические переменные класса содержат информацию, необходимую для создания новых объектов (например в фабрике классов). Например, если вы хотите пронумеровать экземпляры класса, можно использовать статическую переменную для отслеживания последнего используемого номера. Важно отметить, что хорошим тоном при использовании статических переменных класса является использование class_name::х;, а не instance_of_class.x;. Это помогает напомнить программисту, что статические переменные не принадлежат к одному экземпляру класса, и что вам не обязательно создавать экземпляр этого класса. Как вы уже, наверное, заметили, для доступа к static можно использовать оператор области видимости, ::, когда вы обращаетесь к нему через имя класса.

Важно иметь в виду, при отладке или реализации программы с использованием static, что вы не можете инициализировать его внутри класса. В самом деле, если вы решите написать весь код класса в файл заголовка, вы даже не сможете инициализировать статическую переменную внутри файла заголовка; сделайте это в файле .cpp. Кроме того, вам необходимо инициализировать статические члены класса, или их не будет в области видимости. (Синтаксис немного странный: type class_name::static_variable = value.)

У вас также могут быть статические функции класса. Статические функции — это функции, которые не требуют экземпляра класса и вызываются так же, по аналогии со статическими переменным, с именем класса, а не с именем объекта. Например, a_class::static_function();, а не an_instance.function();. Статические функции могут работать только со статическими членами класса, так как они не относятся к конкретным экземплярам класса. Статические функции могут быть использованы для изменения статических переменных, отслеживать их значения — например, вы можете использовать статическую функцию, если вы решили использовать счетчик, чтобы дать каждому экземпляру класса уникальный идентификатор.

Например, вы можете использовать следующий код:

class user
{
  private:
  int id;
  static int next_id;

  public:
  static int next_user_id()
  {
    next_id++;
    return next_id;
  }
  // остальные методы для класса user
  user() // конструктор класса
  {
    id = user::next_id++; // или вызов метода, id = user.next_user_id();
  }
};
int user::next_id = 0;

Обратите внимание, что вы должны включать тип статической переменной, когда вы устанавливаете его!

Строка

user a_user;

установит идентификатор на следующий идентификационный номер, не используемый любым другим объектом user. Обратите внимание, что это хороший стиль объявления идентификатора как константы.

Последнее использование static — глобальная переменная в файле кода. В этом случае использование static указывает, что исходный код в других файлах, которые являются частью проекта, не может получить доступ к переменной. Только код внутри того же файла может увидеть переменную (её область видимости ограничена файлом). Эта техника может быть использована для моделирования объектно-ориентированного кода, потому что она ограничивает видимость переменных и таким образом помогает избежать конфликта имен. Этот способ использования static является пережитком Cи.

Практика

К сожалению, для данной темы пока нет подходящих задач. Если у вас есть таковые на примете, отправте их по адресу: admin@cppstudio.com. Мы их опубликуем!

Автор: Marienko L.
Дата: 10.10.2012
Поделиться:

Комментарии

  1. Vaidokcrunk

    Vaidokcrunk

    Купить Сиалис в Российской Федерации

    Даже если мужчина пытается придерживаться здорового уклада жизни, ежегодно проходит все обследования и занимается спортом, раньше или позже его всё-равно ждут проблемы с потенцией: такова неприятная сущность старения.

    К большому счастью прогрессивная медицина создала [url=http://via-sexgra.ru/shpanskaya-mushka]шпанская мушка отзывы врачей[/url] , что смогут продлить здоровую половую жизнь на полтора десятка лет, не вредя при этом здоровью всех других систем организма. Речь идет о Левитре дженериках, что вы сможете купить на этом сайте via-sexgra.ru

    Тут вас ожидает каталог из пары десятков препаратов, которые десятки лет продаются в США и прошли все нужные процедуры клинического тестирования. В отличие от банальных аптек, в этом онлайн магазине все дженерики продаются по низким расценкам и отправляются клиенту в простой посылке, которая обеспечивает полную анонимность заказа.

    Все продаваемые таблетки производятся на легальных западноевропейских фармацевтических фабриках и сопровождаются всеми нужными документами. Низкая стоимость дженериков обуславливается отсутствием длинной цепочки посредников, как в случае с классической аптекой.

  2. Владимир Александров

    Спасибо большое за статью! Полностью раскрывает суть static переменных! Низкий поклон!

  3. Иван Жуков

    Вообще не понял статьи, будто ее другой человек писал.

    Вы также можете использовать static таким образом, чтобы предотвратить переинициализацию переменной внутри цикла. Например, в следующем коде переменная number_of_times будет равна 100, несмотря на то что строкаstatic int number_of_times = 0; находится внутри цикла, где она, по-видимому, должна исполнятся каждый раз, когда программа доходит до цикла. Хитрость заключается в том, что ключевое слово static препятствует повторной инициализации переменной. Одной из особенностей использования ключевого слова static является то, что оно автоматически устанавливает переменную в ноль для вас

    Что тут, 0 должна быть потому что статик? 1 должна быть потому что должна 1 инициализация пройти за всю функцию?? Почему 100 будет если это статик? в чем ее задача тогда?

     

    • Тарас Чорненький

      Переменная number_of_times будет равна 100, потому что в процессе выполнения цикла она будет инкрементирована 100 раз, а поскольку эта переменная static – инициализирована она будет только один раз.

  4. garjo_099

    Хотя большинство переменных, объявленных внутри класса могут иметь разное значение в каждом экземпляре класса, статические поля класса будут иметь то же значение для всех экземпляров данного класса и даже не обязательно создавать экземпляр этого класса.

    вообще не разобрался в этих строчках и ниже… кто нибудь отзовитесь для ответов на вопросы.

    • Богдан

      Когда ты создаешь объект то ты инициализируется переменная и выделяется память(оператор new с конструктором).

      Наприимер:

      Student s = new Student();
      // Student названия класса
      // s сам объект(со своими свойствами)
      //new оператор выделения памяти для объектов
      //Student() конструктор

      А чтоб использовать статические переменные и статические функции нужно обратится через имя класса и оператор расширения(или доступа) «::«. И их значения не зависят от изменений объекта, только изменения через имя класса

       

      . Эти переменные не зависят от созданных объектов

      • Богдан

        ой з джавой немного попутал и С#  вот код. Позже напишу пример с статикой

        Student s;//уже срабатывает конструктор
        s.s=1;
        Student *s = new Student();
        //здесь мы ссылаемся на память где находится объект
        s->s=1;
    • Богдан

      вот как и обещал ))) написан в MVC. вставь и посмотри результат, надеюсь поймешь

      // asd.cpp: определяет точку входа для консольного приложения.
      //
      
      #include "stdafx.h"
      #include <iostream>
      using namespace std;
      
      class S{
      private:
      protected:
      public:
      	static int s;
      	int n,k;
      	S(){
      		n = 0;k=0;
      	}
      };int S::s = 0;
      
      int _tmain(int argc, _TCHAR* argv[])
      {
      	S::s++;
      	S s;
      	s.k = S::s;
      	S::s +=2;
      	s.n = S::s;
      	cout<<"k = "<<s.k<<endl;
      	cout<<"n = "<<s.n<<endl;
      	cout<<"s.s = "<<s.s<<endl;
      	cout<<"S::s ="<<S::s<<endl;
      	S ss;
      	cout<<"ss.s = "<<ss.s<<endl;
      	S::s++;
      	S sss;
      	cout<<"s.s = "<<s.s<<endl;
      	cout<<"ss.s = "<<ss.s<<endl;
      	cout<<"sss.s = "<<sss.s<<endl;
      	system("pause");
      	return 0;
      }
  5. SashaViper

    А почему в такой ситуации как у меня нумерация начинается с 0, а не с 1?

    #include <iostream>
    #include <string>
    using namespace std;
    
    class user {
    private:
        int id;
        static int next;
    public:
        user() {
            id = user::next++;
        }
        int showId() {
            return id;
        }
    };
    int user::next = 0;
    
    int main() {
        user alex;
        cout << alex.showId();
        user serg;
        cout << serg.showId();
        user olga;
        cout << olga.showId();
        return 0;
    }
    • SashaViper

      Я разобрался)) Извиняюсь… ступил. В конструкторе в строке:

      id = user::next++;

      Сначала присваивается значение переменной, а потом происходит её увеличение на единицу.

Оставить комментарий

Вы должны войти, чтобы оставить комментарий.