Помимо констант и массивов, статическим элементом класса может быть как поле, так и метод (см. п. 9.4 в [1]). Естественно, статические методы предназначены, в первую очередь, для манипуляции статическими полями. Обозначаются поля и методы словом static.
Страуструп Б. на с. 274 в [2] определяет статическое поле как поле, которое является частью класса, но не является частью объекта этого класса. Это означает, что инкапсуляция работает как и для обычных полей, а вот память выделяется не в объекте. Статические поля класса размещаются в статической памяти1 (как глобальные и статические переменные) и создаются в единственном экземпляре, независимо от количества определяемых в программе объектов. Все объекты (даже созданные динамически) разделяют единственную копию статических полей (см. п. п. 9.4.2 в [1]). Более того, все классы-наследники тоже разделяют эту единственную копию (см. главу 8). При этом в класс включается только объявление, а определение статического поля выполняется отдельно за пределами класса (как мы видели ранее на примере статического константного массива).
ПРИМЕЧАНИЕ
Единственным исключением из этого правила являются целочисленные статические константы, которые разрешается инициализировать (определять) непосредственно в классе (см. листинг 2.5).
Естественно, определение должно быть единственным в программе, иначе компоновщик (не компилятор) сообщит о повторном определении. Если определение отсутствует, то мы тоже получим ошибку компоновки.
См. следующую главу.
При определении поля выполняется и его инициализация. Если статическое поле является константным, то инициализация обязательна. Инициализация статических полей выполняется точно так же, как инициализация глобальных и статических Переменных (см. п. п. 9.4.2/7 в [1]). Для неконстантных статических полей элементарных типов при отсутствии явной инициализации выполняется обнуление. Для статических полей неэлементарных типов, естественно, вызываются конструкторы: либо явным образом конструктор инициализации, либо конструктор по умолчанию (при отсутствии явной инициализации).
Продемонстрируем все это на элементарном примере (листинг 4.21).
Листинг 4.21. Статические поля
#include <iostream> #include <string> using namespace std; class Person { string Fio;
int year;
public: Person()
: FioCLippman"), year(1953) {}
Person(string fio, int y) { Fio = fio; year = y; } void print() const;
};
class StaticField
{ static const int m91 = 1;
static const int m92;
static const double m03;
Static int m94;
static double m65;
static const Person p;
static Person t; public:
static void print();
};
// демонстрационный класс // неэлементарный тип
// конструктор по умолчанию
//
//
// // // // // // //
конструктор инициализации вывод полей на экран
инициализированная константа неинициализированное константное поле константное поле нецелого типа неконстантное поле целого типа неконстантное поле нецелого типа константное поле неэлементарного ;гипа неконстантное поле неэлементарного типа
// статический метод
//
const int StaticField::m92 = 2; //
const double StaticField::m03 = 3.1;
int StaticField::m94; //
double StaticField::m05; //
const Person StaticField::p("Kupaev'
Person StaticField::t; //
//
void StaticField::print() { cout << m01 << endl;
cout << m02 << endl;
cout << m03 << endl;
cout << m04 << endl;
cout << m05 << endl;
определение статических полей обязательная инициализация
// обязательная инициализация инициализация по умолчанию (ноль) инициализация по умолчанию (ноль) , 1999); // конструктор инициализации конструктор по умолчанию определение статического метода
p.printO ; t.printO ;
}
void Person::print() const // константный нестатический метод
{ cout << Fio <<',' << year << endl: } int main()
{ StaticField::print(); // вывод значений статических полей
return 0:
}
В этой программе класс Person написан только для демонстрации статических полей неэлементарного типа. В нем определено два конструктора — по умолчанию и инициализации, — чтобы продемонстрировать вызовы при инициализации статических полей типа Person.
В классе StaticField объявляется ряд статических полей, константных и неконстантных. Для вывода значений на экран объявляется статический метод pr i nt (). После определения класса задано определение статических полей. Для константных статических полей (т02 и тОЗ) инициализацию писать обязательно. Неконстантные статические поля элементарных типов (т04 и т05) инициализируются по умолчанию — выполняется обнуление. И наконец, определение статических полей типа Person демонстрирует вызов конструкторов. Поле, р должно быть обязательно проинициализировано, так как является константным. Именно для его инициализации в классе Person реализован конструктор инициализации. Поле t не является константным, поэтому определяется без явной инициализации. Однако для него вызывается конструктор по умолчанию, что можно наблюдать при вызове статического метода print() в главной программе. Программа выведет на экран следующее:
1 // mOl - константа, инициализируется в классе
2 // m02 - константа, инициализируется явно
3.1 // m03 - константа, инициализируется явно
0 // m04 - не константа, инициализируется по умолчанию (0)
0 // m05 - не константа, инициализируется по умолчанию (0)
Kupaev,1999 // P - константа, инициализируется явно
Lippman,1953 // t - не константа, инициализируется неявно
Обратите внимание: статический метод работает, хотя не определен ни один объект типа StaticField. Именно поэтому вызов метода пишется с префиксом — именем класса:
StaticField::print();
В отличие от этого метода, метод print О класса Person вызывается для конкретных объектов р и t.
Определения статических полей на первый взгляд противоречат всем принципам инкапсуляции: поля объявлены приватными, но значения им присваиваются «в открытую». Однако, во-первых, такая инициализация разрешена только в определении, которое обязан предоставить создатель класса, иначе программа не пройдет компоновку. Во-вторых, определение-то у нас единственное. Таким образом, механизм защиты данных работает по-прежнему — присвоить значение приватной статической переменной «в открытую» в другом месте не получится.
Теперь разберемся со статическими методами, которые существенно отличаются от обычных. Статические методы называют методами класса. Статический метод можно вызвать для объекта:
object. staticmethodO
Кроме того, статический метод можно вызывать для класса независимо от определения объектов класса:
class: : staticmethodO
Так как статический метод не «приписан» к объекту, он не получает указателя this в качестве параметра. Ни конструкторы, ни деструктор, ни операция присваивания не могут быть статическими. Статические методы не могут быть константными. Статические методы не могут быть виртуальными (см. главу 9).
Статические методы позволяют решить одну небольшую проблему, которая иногда возникает при реализации конструкторов. Яркий пример — класс комплексных чисел.
Программируя и занимаясь финансовой деятельностью в интернете, например продавая свои программы необходима финансовая безопасность в интернете о которой подробнее можно узнать тут.
Комплексные числа имеют две формы записи: в декартовых и полярных координатах. Обе формы записи задаются парой действительных чисел, только в первом варианте эти числа являются абсциссой и ординатой, а во втором — радиусом и углом. Прототипы обоих конструкторов, очевидно, одинаковы:
Complex(const double &а, const double &b);
|