Что означает static при описании поля. Статические члены класса

Ключевое слово static

Иногда требуется определить такой член класса, который будет использоваться независимо от всех остальных объектов этого класса. Как правило, доступ к члену класса организуется посредством объекта этого класса, но в то же время можно создать член класса для самостоятельного применения без ссылки на конкретный экземпляр объекта. Для того чтобы создать такой член класса, достаточно указать в самом начале его объявления ключевое слово static .

Если член класса объявляется как static, то он становится доступным до создания любых объектов своего класса и без ссылки на какой-нибудь объект. С помощью ключевого слова static можно объявлять как переменные, так и методы. Наиболее характерным примером члена типа static служит метод Main(), который объявляется таковым потому, что он должен вызываться операционной системой в самом начале выполняемой программы.

Для того чтобы воспользоваться членом типа static за пределами класса, достаточно указать имя этого класса с оператором-точкой. Но создавать объект для этого не нужно. В действительности член типа static оказывается доступным не по ссылке на объект, а по имени своего класса.

Переменные, объявляемые как static, по существу, являются глобальными. Когда же объекты объявляются в своем классе, то копия переменной типа static не создается. Вместо этого все экземпляры класса совместно пользуются одной и той же переменной типа static. Такая переменная инициализируется перед ее применением в классе.

Пример использования ключевого слова static:

Using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class myCircle { // 2 метода, возвращающие площадь и длину круга public static double SqrCircle(int radius) { return Math.PI * radius * radius; } public static double LongCircle(int radius) { return 2 * Math.PI * radius; } } class Program { static void Main(string args) { int r = 10; // Вызов методов из другого класса // без создания экземпляра объекта этого класса Console.WriteLine("Площадь круга радиусом {0} = {1:#.##}",r,myCircle.SqrCircle(r)); Console.WriteLine("Длина круга равна {0:#.##}",myCircle.LongCircle(r)); Console.ReadLine(); } } }

На применение методов типа static накладывается ряд следующих ограничений:

    В методе типа static должна отсутствовать ссылка this, поскольку такой метод не выполняется относительно какого-либо объекта

    В методе типа static допускается непосредственный вызов только других методов типа static, но не метода экземпляра из того самого же класса. Дело в том, что методы экземпляра оперируют конкретными объектами, а метод типа static не вызывается для объекта. Следовательно, у такого метода отсутствуют объекты, которыми он мог бы оперировать

    Аналогичные ограничения накладываются на данные типа static. Для метода типа static непосредственно доступными оказываются только другие данные типа static, определенные в его классе. Он, в частности, не может оперировать переменной экземпляра своего класса, поскольку у него отсутствуют объекты, которыми он мог бы оперировать

Статические конструкторы

Конструктор можно также объявить как static. Статический конструктор, как правило, используется для инициализации компонентов, применяемых ко всему классу, а не к отдельному экземпляру объекта этого класса. Поэтому члены класса инициализируются статическим конструктором до создания каких-либо объектов этого класса:

Using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class MyClass { public static int a; public int b; // Статический конструктор static MyClass() { a = 10; } // Обычный конструктор public MyClass() { b = 12; } } class Program { static void Main(string args) { Console.WriteLine("Доступ к экземпляру класса a: " + MyClass.a); MyClass obj = new MyClass(); Console.WriteLine("Доступ к экземпляру класса b: " + obj.b); Console.ReadLine(); } } }

Обратите внимание на то, что конструктор типа static вызывается автоматически, когда класс загружается впервые, причем до конструктора экземпляра. Из этого можно сделать более общий вывод: статический конструктор должен выполняться до любого конструктора экземпляра. Более того, у статических конструкторов отсутствуют модификаторы доступа - они пользуются доступом по умолчанию, а следовательно, их нельзя вызывать из программы.

Статические классы

Класс можно объявлять как static. Статический класс обладает двумя основными свойствами. Во-первых, объекты статического класса создавать нельзя . И во-вторых, статический класс должен содержать только статические члены. Статический класс создается по приведенной ниже форме объявления класса, видоизмененной с помощью ключевого слова static.

static class имя класса { // ...

Статические классы применяются главным образом в двух случаях. Во-первых, статический класс требуется при создании метода расширения . Методы расширения связаны в основном с языком LINQ. И во-вторых, статический класс служит для хранения совокупности связанных друг с другом статических методов.

Члены класса могут использоваться с ключевым словом static. В данном контексте его значение сходно с тем, которое оно имеет в С. Когда член класса объявляется как статический, то тем самым компилятору дается указание, что должна существовать только одна копия этого члена, сколько бы объектов этого класса ни создавалось. Статический член используется совместно все­ми объектами данного класса. Все статические данные инициализируются нулями при создании первого объекта, и другая инициализация не предусмотрена.

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

В качестве примера рассмотрим следующую программу:

#include
class counter {
static int count;
public:
void setcount(int i) {count = i;};
void showcount () {cout << count << " "; }
};
int counter::count; // определение count
int main() {
counter a, b;
a.showcount (); // выводит 0
b.showcount (); // выводит 0
a.setcount (10); // установка статического count в 10
a.showcount (); // выводит 10
b.showcount (); // также выводит 10
return 0;
}

В первую очередь обратим внимание на то, что статическая переменная целого типа count объяв­ляется в двух местах: в классе counter и затем - как глобальная переменная. Borland С++ иници­ализирует count нулем. Именно поэтому первый вызов showcount() выводит в качестве результата нуль. Затем объект а устанавливает count равным 10. После этого оба объекта а и b выводят с помощью функции showcount() одну и ту же величину, равную 10. Поскольку существует только одна копия count, используемая совместно объектами а и b, то на экран выводится в обоих слу­чаях значение 10.

Также можно иметь статические функции-члены. Статические функции-члены не могут прямо ссылаться на нестатические данные или нестатические функции, объявленные в их классе. Причи­ной тому является отсутствие для них указателя this, так что нет способа узнать, с какими именно нестатическими данными работать. Например, если имеется два объекта класса, содержащие стати­ческую функцию f(), и если f() пытается получить доступ к нестатической переменной var, опреде­ленной этим классом, то как можно определить, какую именно копию var следует использовать? Компилятор не может решить такую проблему. В этом заключается причина того, что статичес­кие функции могут обращаться только к другим статическим функциям или статическим данным. Также статические функции не могут быть виртуальными или объявляться с модификаторами const иди volatile. Статическая функция может вызываться либо с использованием объекта класса, либо с использованием имени класса и оператора области видимости. Тем не менее не надо забы­вать, что даже при вызове статической функции с использованием объекта, ей не передается указатель this.

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

#include


class access {
static enum access_t acs;
// ...
public:


{
return acs;
}
// ...
};

int main()
{
access obj1, obj2;
access::set_access(locked); // вызов с использованием имени класса
// ... код

if (obj2.get_access()==unlocked) { // вызов с помощью объекта

cout << "Access resource.\n";
}
else cout << "Locked out.\n";
// ...
return 0;
}

При запуске этой программы на экране появится «locked out». Обратим внимание, что функция set_access() вызвана с именем класса и оператором области видимости. Функция get_access() вы­звана с объектом и оператором «точка». При вызове статической функции может использовать­ся любая из этих форм и обе они дают одинаковый эффект. Стоит поэкспериментировать немно­го с этой программой, чтобы убедиться в правильности понимания хода ее работы.

Как отмечалось, статические функции имеют прямой доступ только к другим статическим фун­кциям или статическим данным в пределах одного и того же класса. Чтобы проверить это, по­пробуем откомпилировать следующую версию программы:

// данная программа содержит ошибку и не будет компилироваться
#include
enum access_t {shared, in_use, locked, unlocked};
// класс контролирует редкий ресурс
class access {
static enum access_t acs;
int i; // не статический
// ...
public:
static void set_access (enum access_t a) {acs = a;}
static enum access_t get_access()
{
i = 100; // не будет компилироваться
return acs;
}
// ...
};
enum access_t access::acs; // определение acs
int main()
{
access obj1, obj2;
access::set_access(locked); // вызов с помощью имени класса
// ... код
// может ли obj2 обращаться к ресурсу
if(obj2.get_access()==unlocked) { // вызов с помощью объекта
access::set_access(in_use); // вызов с помощью имени класса
cout << "Access resource.\n";
}
else cout << "Locked out.\n";
// ...
}

Эта программа не будет откомпилирована, поскольку функция get_access() пытается получить доступ к нестатической переменной.

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

Кроме модификатора доступа, перед названием поля, метода или свойства можно написать ключевое слово static .
«static » означает, что данное поле, метод или свойство будет принадлежать не каждому объекту класса, а всем им вместе.

Классический пример: как определить, сколько объектов одного класса было создано? Для решения данного вопроса, как раз и служат статические поля и методы .

Давайте разберем на примере с тиграми. Определим класс «Tiger ». Если мы запишем поле класса вот так: public int count; то данное поле будет у каждого объекта, и у каждого объекта оно будет своё. Причем, если не создано ни одного объекта, то это поле не будет существовать вообще.
Поэтому cделаем это поле статическим (static ).

Создадим конструктор, в котором будем увеличить счетчик count при создании каждого нового объекта:
public Tiger() { count++; }.
Здесь же мы можем задавать индивидуальные характеристики тигра: вес, рост, кличка.

Также напишем статический метод, который выводит количество созданных объектов:
public static void ShowNumberOfObjects().

Тогда в нашем консольном приложении будут два класса:

Public class Tiger { public static int count; public Tiger() { count++; } public static void ShowNumberOfObjects() { Console.WriteLine("Тигров = {0}", Tiger.count.ToString()); } } class Program { static void Main(string args) { // Чему равно число тигров без создания объектов? Tiger.ShowNumberOfObjects(); // 0, т.к. мы пока не создали объекты // Создадим 3 тигров Tiger t1 = new Tiger (); Tiger t2 = new Tiger (); Tiger t3 = new Tiger (); Tiger.ShowNumberOfObjects(); // выйдет 3 тигра Console.ReadLine(); } }

Результат: 3.

Вывод. Статический метод позволяет вызывать его, не имея в наличии ни одного объекта. Вместо имени объекта при вызове метода указывается имя класса Tiger: Tiger.ShowNumberOfObjects();

Отличия статического метода от нестатического:

1. Для вызова статического метода не нужен объект.
2. Внутри статического метода недоступна переменная this, указывающая на объект, соответственно недоступны все нестатические поля этого класса, т.к. как нет объекта.
3. Внутри обычного метода доступны как статические, так и нестатические поля.
4. Начиная с C# 4.0 появилась возможность и сам класс сделать статическим.

Иногда создают классы, которые состоят только из статических методов, как, например, класс Math. По сути, такие классы являются контейнерами глобальных функций, однако это отходит от концепции ООП. Также нельзя будет создавать, соответственно, и экземпляры статического класса.

Теперь разберемся с понятием «структура» и выясним ее отличие от класса.

Урок 25. Статические функции и элементы данных

До настоящего момента каждый создаваемый вами объект имел свой собственный набор элементов данных. В зависимости от назначения вашего приложения могут быть ситуации, когда объекты одного и того же класса должны совместно использовать один или несколько элементов данных. Например, предположим, что вы пишете программу платежей, которая отслеживает рабочее время для 1000 служащих. Для определения налоговой ставки программа должна знать условия, в которых работает каждый служащий. Пусть для этого используется переменная класса state_of_work. Однако, если все служащие работают в одинаковых условиях, ваша программа могла бы совместно использовать этот элемент данных для всех объектов типа employee. Таким образом, ваша программа уменьшает необходимое количество памяти, выбрасывая 999 копий одинаковой информации. Для совместного использования элемента класса вы должны объявить этот элемент как static (статический). Этот урок рассматривает шаги, которые вы должны выполнить для совместного использования элемента класса несколькими объектами. К концу этого урока вы освоите следующие основные концепции:

    C++ позволяет иметь объекты одного и того же типа, которые совместно используют один или несколько элементов класса.

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

    Для создания совместно используемого элемента данных класса вы должны предварять имя элемента класса ключевым словом static.

    После того как программа объявила элемент класса как static, она должна объявить глобальную переменную (вне определения класса), которая соответствует этому совместно используемому элементу класса.

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

СОВМЕСТНОЕ ИСПОЛЬЗОВАНИЕ ЭЛЕМЕНТА ДАННЫХ

Обычно, когда вы создаете объекты определенного класса, каждый объект получает свой собственный набор элементов данных. Однако возможны такие ситуации, при которых объектам одного и того же класса необходимо совместно использовать один или несколько элементов данных (статические э лементы данных). В таких случаях объявляйте элементы данных как общие ил и частные, а затем предваряйте тип ключевым словом static, как показано ниже:

private: static int shared_value;

После объявления класса вы должны объявить элемент как глобальную переменную вне класса, как показано ниже:

int class_name::shared_value;

Следующая программа SHARE_IT.CPP определяет класс book_series, совместно использующий элемент page_count, который является одинаковым для всех объектов (книг) класса (серии). Если программа изменяет значение этого элемента, изменение сразу же проявляется во всех объектах класса:

#include

#include

class book_series

{ public: book_series(char *, char *, float); void show_book(void); void set_pages(int) ; private: static int page_count; char title; char author[ 64 ]; float price; };

int book_series::page__count;

void book_series::set_pages(int pages)

{ page_count = pages; }

book_series::book_series(char *title, char *author, float price)

{ strcpy(book_series::title, title); strcpy(book_series::author, author); book_series::price = price; }

void book_series:: show_book (void)

{ cout << "Заголовок: " << title << endl; cout << "Автор: " << author << endl; cout << "Цена: " << price << endl; cout << "Страницы: " << page_count << endl; }

{ book_series programming("Учимся программировать на C++", "Jamsa", 22.95); book_series word("Учимся работать с Word для Windows", "Wyatt", 19.95); word.set_pages(256); programming.show_book (); word.show_book() ; cout << endl << "Изменение page_count " << endl; programming.set_pages(512); programming.show_book(); word.show_book(); }

Как видите, класс объявляет page_count как static int. Сразу же за определением класса программа объявляет элемент page_count как глобальную переменную. Когда программа изменяет элемент page_count, изменение сразу же проявляется во всех объектах класса book_series.

Совместное использование элементов класса

В зависимости от вашей программы возможны ситуации, когда вам потребуется совместно использовать определенные данные несколькими экземплярами объекта. Для этого объявите такой элемент как static. Далее объявите этот элемент вне класса как глобальную переменную. Любые изменения, которые ваша программа делает с этим элементом, будут немедленно отражены в объектах данного класса.

Использование элементов с атрибутами public static, если объекты не существуют

Как вы только что узнали, при объявлении элемента класса как static этот элемент совместно используется всеми объектами данного класса. Однако возможны ситуации, когда программа еще не создала объект, но ей необходимо использовать элемент. Для использования элемента ваша программа должна объявить его как public и static. Например, следующая программа USЕ_MBR.CPP использует элемент page_count из класса book_series, даже если объекты этого класса не существуют:

#include

#include

class book_series

{ public: static int page_count; private: char title ; char author; float price; };

int book_series::page_count;

void main(void) { book_series::page_count = 256; cout << "Текущее значение page_count равно " << book_series::page_count << endl; }

В данном случае, поскольку класс определяет элемент класса page_count как public, программа может обратиться к этому элементу класса, даже если объекты класса book_series не существуют.

ИСПОЛЬЗОВАНИЕ СТАТИЧЕСКИХ ФУНКЦИЙ-ЭЛЕМЕНТОВ

Предыдущая программа иллюстрировала использование статических элементов данных. Подобным образом C++ позволяет вам определить статические функции-элементы (методы). Если вы создаете статический метод, ваша программа может вызывать такой метод, даже если объекты не были созданы. Например, если класс содержит метод, который может быть использован для данных вне класса, вы могли бы сделать этот метод статическим. Ниже приведен класс menu, который использует esc-последовательность драйвера ANSI для очистки экрана дисплея. Если в вашей системе установлен драйвер ANSI.SYS, вы можете использовать метод clear_screen для очистки экрана. Поскольку этот метод объявлен как статический, программа может использовать его, даже если объекты типа menu не существуют. Следующая программа CLR_SCR.CPP использует метод clear_screen для очистки экрана дисплея:

#include

{ public: static void clear_screen(void); // Здесь должны быть другие методы private: int number_of_menu_options; };

void menu::clear_screen(void)

{ cout << "\033" << "}

Понравилась статья? Поделиться с друзьями: