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

Каждый объект одного и того же класса имеет собственную копию данных класса. Можно сказать, что данные класса тиражируются при каждом определении объекта этого класса. Отличаются они друг от друга именно по "привязке" к тому или иному объекту. Это не всегда соответствует требованиям решаемой задачи. Например, при формировании объектов класса может потребоваться счетчик объектов. Безусловно, такой счетчик можно сделать компонентом класса, но иметь его нужно только в единственном числе. Чтобы компонент класса был в единственном экземпляре и не тиражировался при создании каждого нового объекта класса, он должен быть определен в классе как статический и иметь атрибут static.

Статические поля класса. Счетчик объектов класса.

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

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

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

Рассмотрим пример. Реализуем класс object_, в статическом члене которого хранится число существующих в каждый момент времени объектов типа object_.

# include <iostream>
# include <string.h>
using namespace std;

class object_{ 
    char *str;
public:
	//статическое поле класса
	static int num_obj;
	
	//конструктор
    	object_ (char *s){
        	str = new char [strlen (s) + 1]; 
		strcpy ( str, s ); 
		cout <<"Create " << str <<'\n';

		// увеличиваем значение счетчика 
		num_obj ++ ; 
    	} 

	//деструктор
    	~object_ (){ 
		cout <<"Destroy " << str << '\n'; 
		delete str;
 
		// уменьшаем значение счетчика 
		num_obj --; 
    	} 
}; 

// Инициализация. Об этом говорит
// ключевое слово int! 
int object_::num_obj = 0; 

// создание глобальных объектов
object_ s1 ("First global object."); 
object_ s2 ("Second global object."); 

// вспомогательная функция
void f (char *str) { 
	 // Локальный объект
     	object_ s(str); 
	 // явное обращение к статическому полю
	 // без указания объекта
     	cout <<"Count of objects - " <<object_::num_obj<<".\n"; 
     	cout <<"Worked function f()" <<".\n";
} 

void main () { 
	// явное обращение к статическому полю
     	cout <<"Now, count of objects " <<object_::num_obj<<".\n";
	object_ M ("Object in main ()."); 

	// обращение к статическому полю через объект
     	cout <<"Now, count of objects" << M.num_obj <<".\n";

	f ("Local object."); 
        f ("Another local object."); 

     	cout << "Before finish main() count of objects - " <<object_::num_obj<<".\n";
} 

Результаты работы программы:

Create First global object.
Create Second global object.
Now, count of objects 2.
Create Object in main ().
Now, count of objects3.
Create Local object.
Count of objects - 4.
Worked function f().
Destroy Local object.
Create Another local object.
Count of objects - 4.
Worked function f().
Destroy Another local object.
Before finish main() count of objects - 3.
Destroy Object in main ().
Destroy Second global object.
Destroy First global object.
Обратим внимание, что конструкторы для глобальных объектов вызываются до функции main (), а деструкторы после main().

На статические данные класса распространяются правила статуса доступа. Если статические данные имеют статус private, то к ним извне можно обращаться через компонентные функции. Другими словами, получается, что, если к моменту необходимости обращения к статическому полю типа private, объект класса еще не определен, обращение невозможно. Согласитесь, хотелось бы иметь возможность обойтись без имени конкретного объекта при обращении к статическим данным класса. Эта задача решается с помощью статической компонентной функции-метода.

Статические методы класса.

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

Кроме того, статическую компонентную функцию можно вызвать следующим образом:

имя_класса::имя_статической_функции

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

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

Рассмотрим пример:

# include <iostream>
using namespace std;

class prim{ 

     	int numb;
	// статическое поле
	static int stat_; 

public: 
     	prim (int i) { 
		numb=i; 
     	}
 
     	/*
	Статическая функция. Указатель this не определен, 
	поэтому выбор объекта осуществляется по явно
	переданному указателю. Поле stat_ не требует
	указателя на объект,т.к. оно общий для всех объектов класса prim. 
     	*/ 
     	static void func (int i, prim *p = 0) {
		// если хотя бы один объект есть 
		if(p)
			p->numb = i; 
		// если объектов класса нет
        	else 
			stat_ = i; 
     	} 

	/*
	Статическая функция обращается только к
        статическому члену класса, никаких указателей не требуется. 
	*/
     	static void show(){ 
		 cout<<"stat_="<<stat_<<"\n\n";
	} 

	//показ нестатического члена
	void show2(){
		 cout<<"numb="<<numb<<"\n\n";
	}
};  

// Инициализация статического члена класса. 
int prim::stat_ = 8; 

void main(){ 

     	/*
	До создания объектов типа prim возможен
	единственный способ обращения к статической 
	функции-члену.
	*/ 
     	prim::show (); 

     	// Можно изменить значение статического члена класса. 
     	prim::func(10); 

     	/*
	После создания объекта типа prim можно обратиться
	к статической функции обычным для абстрактных типов способом. 
	*/
	 
	// Создается объект obj и его поле numb 
	// становится равным 23.  
     	prim obj(23);
     	obj.show2(); 

     	// Можно изменить значение созданного объекта. 
     	prim::func(20, &obj); // obj.numb 20. 
	obj.show2(); 

     	obj.func(27, &obj); // obj.numb 27. 
	obj.show2(); 
}
PQ VPS сервера в 28+ странах.