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



С помощью модификатора static можно описать статические поля и методы класса.

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

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

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

 

class A

{

public:

static int count;

}

A::count = 0;

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

/* будет выведено одно и то же */

A *a, b; * cout

 

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

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

Классическое применение статических полей — подсчет объектов. Для этого в классе объявляется целочисленное поле, которое увеличивается в конструкторе и уменьшается в деструкторе.

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

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

 

Константные объекты

Если создать представитель класса с модификатором const, то компилятор будет проинформирован, что содержимое объекта не должно изменяться после инициализации. Чтобы предотвратить изменение значений элементов константного объекта, компилятор генерирует сообщение об ошибке, если объект используется с неконстантной функцией-элементом.

Константная функция-элемент, объявляемая с ключевым словом const после списка параметров, должна удовлетворять следующим правилам:

• она не может изменять значение элементов данных класса;

• не может вызывать неконстантные функции-элементы класса;

• может вызываться как для константных, так и неконстантных объектов класса.

Для того чтобы сделать функцию константной, необходимо указать ключевое слово const после прототипа функции, но до начала тела функции. Если объявление и определение функции разделены, то модификатор const необходимо указать дважды – как при объявлении, так и при ее определении. Те методы, которые только лишь считывают данные из поля класса, имеет смысл делать константными, поскольку у них нет необходимости изменять значения полей объектов класса. Например:

 

class CCoord

{

int iX, iY;

public:

void SetCoord(int _iX, int _iY);

void GetCoord(int &_iX, int &_iY) const;

};

 

void CCoord::SetCoord(int _iX, int _iY)

{ iX = _iX; iY = _iY; }

 

void CCoord::GetCoord(int &_iX, int &_iY) const

{ _iX = iX; _iY = iY; }

 

int main(void)

{

CCoord c1; //создаем неконстантный объект

const CCoord c2; //создаем константный объект

int x, y;

c1.SetCoord(10,10); /* - разрешено – вызов не-константной функции для неконстантного объекта */

c2.SetCoord(10,10); /* - запрещено – вызов не-константной функции для константного объекта */

c1.GetCoord(x, y); /* - разрешено: вызов констант-ной функции для неконстантного объекта */

c2.GetCoord(x, y); /* - разрешено: вызов констант-ной функции для константного объекта */

return 0;

}

 

Обычно константные объекты создают для того, чтобы получить гарантии того, что данные объекта невозможно будет изменить. Однако иногда случаются ситуации, когда вы хотите создать объект-константу, имеющий определенное поле, которое нужно будет изменять, несмотря на то, что сам объект является константой. Для этих целей необходимо соответствующее поле объявить со спецификатором mutable. Например, объявив в предыдущем примере поля iX, iY следующим образом:

 

mutable int iX, iY;

 

мы сможем создать константную функцию ResetCoord(10,10); разрешив тем самым модификацию полей константного объекта:

 

class CCoord

{

mutable int iX, iY;

public:

void SetCoord(int _iX, int _iY);

void ResetCoord(int _iX, int _iY) const;

void GetCoord(int &_iX, int &_iY) const;

};

 

void CCoord::SetCoord(int _iX, int _iY)

{ iX = _iX; iY = _iY; }

 

void ResetCoord(int _iX, int _iY) const

{ iX = _iX; iY = _iY; }

 

void CCoord::GetCoord(int &_iX, int &_iY) const

{ _iX = iX; _iY = iY; }

 

int main(void)

{

CCoord c1;

const CCoord c2;

int x, y;

c1.SetCoord(10,10); /* - разрешено – вызов не-константной функции для неконстантного объекта */

c2.SetCoord(10,10); /* - запрещено – вызов не-константной функции для константного объекта */

c1.GetCoord(x, y); /* - разрешено: вызов констант-ной функции для неконстантного объекта */

c2.GetCoord(x, y); /* - разрешено: вызов констант-ной функции для константного объекта */

c2.ResetCoord(10, 10); /* - разрешено, т.к. iX, iY объявлены со спецификатором mutable */

return 0;

}

 

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

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

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

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

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

В качестве примера ниже приведено описание двух функций, дружественных классу monster. Функция kill является методом класса hero, а функция steal_ammo не принадлежит ни одному классу. Обеим функциям в качестве параметра передается ссылка на объект класса monster.

 

class monster; // Предварительное объявление класса

class hero

{

void kill(monster );

};

class monster

{

friend int steal_ammo(monster );

/* Класс hero должен быть определен ранее */

friend void hero::kill(monster );

};

int steal_ammo(monster M){return —M.ammo;}

void hero::kill(monster M){M.health = 0; M.ammo = 0;}

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

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

class hero{

… friend class mistress;}

class mistress{

… void f1();

void f1();}

 

Функции f1 и f2 являются дружественными по отношению к классу hero (хотя и описаны без ключевого слова friend) и имеют доступ ко всем его полям.

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

Контейнерные классы

Контейнерные классы – это классы, которые содержат в своем описании один или несколько объектов или указатели на объекты. В этом случае имеет место отношение «содержит».

 

//f1.h

#include <iostream.h>

class Tail

{int length;

public:

Tail(int n) {length=n;}

int GetTail() {return length;} };

class Dog {Tail tail; public:

Dog(int n):tail(n) {};

void DisplayPar() {cout<<tail.GetTail()<<endl; return;} };

//f1.cpp

#include "f1.h" void main()

{ Dog d(20);

d.DisplayPar(); }

 

Сначала инициализируются все поля–объекты, которые содержатся в описании класса, причем в том порядке, в котором они объявлены. Деструкторы вызываются в порядке, обратном инициализации.

 

Наследование классов

Как известно, наследование - это возможность использования в наследуемом классе функционала наследуемого класса. В С++ существует два вида наследования:

- простое;

- множественное

В других современных языках программирования, дружественное наследование не используется.

Простое наследование – это такое наследование, при котором порождаемые классы наследуют методы и свойства одного базового класса.

Множественное наследование - родителей может быть несколько.

При наследовании не существует ограничений на:

а) на количество производных классов;

б) на длину цепочки наследования

Синтаксис наследования: для того, чтобы унаследовать дочерний класс от родительского класса, необходимо указать имя родительского класса, разделить их символом «:», также в языке С++ перед именем родителя можно указать модификатор доступа.

 

#include <iostream>

using namespace std;

 

class FirstClass // базовый класс

{

protected: // спецификатор доступа к элементу value

int value;

public:

FirstClass()

{

value = 0;

}

 

FirstClass( int input )

{

value = input;

}

 

void show_value()

{

cout << value << endl;

}

};

 

class SecondClass : public FirstClass // производный класс

{

public:

SecondClass() : FirstClass () // конструктор класса SecondClass вызывает конструктор класса FirstClass

{}

 

SecondClass(int inputS) : FirstClass (inputS) // inputS передается в конструктор с параметром класса FirstClass

{}

 

void ValueSqr () // возводит value в квадрат. Без спецификатора доступа protected эта функция не могла бы изменить значение value

{

value *= value;

}

};

 

int main()

{

setlocale(LC_ALL, "rus");

 

FirstClass F_object(3); // объект базового класса

cout << "value F_object = ";

F_object.show_value();

 

SecondClass S_object(4); // объект производного класса

cout << "value S_object = ";

S_object.show_value(); // вызов метода базового класса

 

S_object.ValueSqr(); // возводим value в квадрат

cout << "квадрат value S_object = ";

S_object.show_value();

 

//F_object.ValueSqr(); // базовый класс не имеет доступа к методам производного класса

 

cout << endl;

return 0;

}

 


Дата добавления: 2019-09-13; просмотров: 311; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!