Статические элементы класса

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

Статические поля

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

Эти поля существуют для всех объектов класса в единственном экземпляре, то есть не дублируются.

Особенности статических полей.

- Память под статическое поле выделяется один раз при его инициализации независимо от числа созданных объектов.

- Статические поля доступны как через имя класса, так и через имя объекта:

На статические поля распространяется действие спецификаторов доступа

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

class A{

public:

static int cout;

 

};

int A::cout;

A b,*c;

int main()

{

cout<<A::cout<<endl;//10

cout<<b.cout<<endl;//10

cout<<c->cout<<endl;//10

A::cout=100;

cout<<A::cout<<endl;//10

cout<<b.cout<<endl;//10

cout<<c->cout<<endl;//10

/////////////////////////////

cin.get();

return 0;

}

//---------------------------------------------------------------------------

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

Статические методы предназначены для обращения к статическим полям класса. Они могут обращаться непосредственно только к статическим полям и вызывать только другие статические методы класса, поскольку в им не передается скрытый указатель this. Обращение к статическим методам производится так же, как к статическим полям — либо через имя класса, либо, если хотя бы один объект класса уже создан, через имя объекта.

#include <iostream>

using namespace std;

class B{

static int cout;

int data;

 

public:

static void inc_cout(){cout++;}

static int get_cout(){return cout;}

};

int B::cout(13);

int main()

{

B d,*e;

cout<<d.get_cout()<<endl;

d.inc_cout();

cout<<e->get_cout()<<endl;

cin.get();

return 0;

}

//---------------------------------------------------------------------------

Статические методы не могут быть константными (const) и виртуальными (virtual).

Дружественные функции и классы

Иногда желательно иметь непосредственный доступ извне к скрытым полям класса, то есть расширить интерфейс класса. Для этого служат дружественные функции и дружественные классы.

Дружественная функция

Дружественные функции применяются для доступа к скрытым полям класса и представляют собой альтернативу методам.

Правила описания и особенности дружественных функций.

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

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

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

- Одна функция может быть дружественной сразу нескольким классами.

- Использования дружественных функций нужно по возможности избегать.

Дружественный класс

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

 

#include <iostream>

using namespace std;

class TA{

int a;

int b;

public:

int d;

TA (int x=3,int y=4){a=x;b=y;}

friend void print(TA&);

friend class TB;

 

};

class TB{

public:

void inc_TA(TA& inca){inca.a++;};

void inc_TB(TA& incb){incb.b++;};

};

void print(TA &obj)

{cout<<obj.a<<"\t"<<obj.b<<endl;}

 

int main()

{

TA b,*c,d(4,5),*z;

c=new TA();

z=new TA(7,8);

print(b);

print(d); //4 5

print(*c);

print(*z);

 

delete c;

delete z;

 

TB q;

q.inc_TA(d);

q.inc_TB(d);

print(d);//5 6

 

cin.get();

return 0;

}

Объявление friend не является спецификатором доступа и не наследуется.

Деструкторы

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

для локальных объектов — при выходе из блока, в котором они объявлены;

для глобальных — как часть процедуры выхода из main:

для объектов, заданных через указатели, деструктор вызывается неявно при использовании операции delete.

Имя деструктора начинается с тильды (-), непосредственно за которой следует имя класса. Деструктор:

не имеет аргументов и возвращаемого значения;

не может быть объявлен как const или static;

не наследуется;

может быть виртуальным .

Если деструктор явным образом не определен, компилятор автоматически создает пустой деструктор.

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

Указатель на деструктор определить нельзя.

Деструктор можно вызвать явным образом путем указания полностью уточненного имени:

Это может понадобиться для объектов, которым с помощью перегруженной операции new выделялся конкретный адрес памяти. Без необходимости явно вызывать деструктор объекта не рекомендуется.

Перегрузка операций

C++ позволяет переопределить действие большинства операций так, чтобы при использовании с объектами конкретного класса они выполняли заданные функции.

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

. .* ?: :: # ## sizeof

Перегрузка операций осуществляется с помощью методов специального вида (функций-операций) и подчиняется следующим правилам:

при перегрузке операций сохраняются количество аргументов, приоритеты операций и правила ассоциации (справа налево или слева направо), используемые в стандартных типах данных;

для стандартных типов данных переопределять операции нельзя;

функции-операции не могут иметь аргументов по умолчанию;

функции-операции наследуются (за исключением -);

функции-операции не могут определяться как static.

Функцию-операцию можно определить тремя способами: она должна быть либо методом класса, либо дружественной функцией класса, либо обычной функцией.

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

Функция-операция содержит ключевое слово operator, за которым следует знак переопределяемой операции:

тип operator операция ( список параметров) { тело функции }