Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЯиМП.doc
Скачиваний:
3
Добавлен:
29.07.2019
Размер:
298.5 Кб
Скачать

Создание классов

Лекция 2

Объекты

Объект – это структура, содержащая данные и процедуры для их обработки.

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

Объекты выполняют обработку данных с помощью методов.

Классы

Класс – это шаблон, который определяет поля и методы создаваемых объектов. После создания класса его имя становится новым типом данных.

Индивидуальные объекты называются экземплярами класса. Термины «объект» и «экземпляр класса» эквивалентны.

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

Описание класса

class имя_класса { данные-члены класса;

функции-члены класса;

} [список_объектов];

Если список_объектов отсутствует, то объекты объявляются в программе по мере необходимости.

Данные-члены (data members) часто называют полями или свойствами, а функции-члены (member function) – методами. Поля и методы называются элементами класса.

Закрытые и открытые элементы класса

Закрытые элементы класса доступны только для элементов своего класса, открытые – доступны для других частей программы, в которой содержится класс.

class имя_класса {

[private:]

описание скрытых элементов

public:

описание открытых элементов

} ;

Все методы класса имеют доступ ко всем членам класса, в том числе и к закрытым.

Действие любого спецификатора (public, private) распространяется до следующего спецификатора или до конца класса. По умолчанию – private. Можно задавать несколько секций private и publiс.

Спецификатор protected будет рассмотрен позднее.

Поля и методы класса

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

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

Методы класса могут быть как определены в классе, так и объявлены (приведены только заголовки).

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

Если метод только объявлен внутри класса, то его нужно определить в другом месте программы с помощью операции доступа к области видимости «::»:

тип имя_класса::имя_метода (параметры) {

/* тело метода */ }

Создание объектов

Чтобы создать объект (экземпляр класса) нужно объявить в программе переменную типа «класс».

Каждый объект имеет собственные копии полей, но методы у них общие.

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

Если поле описано как статическое (static), то оно существует в единственном экземпляре (общее для всех объектов класса).

Статические методы предназначены для обращения к статическим полям. Они могут обращаться только к статическим полям и вызывать другие статические методы класса.

Чтобы обратиться к статическому методу вне класса нужно перед ним указать имя класса и оператор ::.

Пример класса

#include <iostream>

using namespace std;

class point{

public:

int x;

int y; };

class rectangle{

public:

point top_left;

point bottom_right;

int perim() {return 2*(bottom_right.x - top_left.x)+

2*(bottom_right.y - top_left.y); }; };

int main(){

rectangle r;

r.top_left.x=0; r.top_left.y=0;

r.bottom_right.x=100; r.bottom_right.y=50;

cout<< "P=" << r.perim() << endl;

return 0; }

Конструкторы

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

Имя конструктора совпадает с именем класса. Конструкторы можно перегружать.

Свойства конструктора:

  • не указывается тип возвращаемого значения;

  • не может возвращать значение;

  • не наследуется.

Необходимость использования конструкторов вызвана тем, что элементы класса не могут получать начальные значения в определении класса другим способом.

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

Деструкторы

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

Имя деструктора совпадает с именем класса, но имеет префикс «~» (тильда).

Деструктор не имеет аргументов и не может возвращать значение, поэтому в классе он всегда один.

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

Перегрузка конструктора (пример)

#include <iostream>

using namespace std;

#include <iomanip>

class ex_class { int x;

public: ex_class() {x=0;}

ex_class(int a) {x=a;}

int value() {return x;} };

void main (){

ex_class c1; // объявление объекта без явного задания значений

ex_class c2(5); // объявление объекта с явным значением

ex_class c3[5]; //объявление массива объектов без явного

//задания значений

ex_class c4[5]={1,2,3,4,5}; // объявление массива объектов с

//явными значениями

cout << c1.value() << " ," << c2.value() << endl;

for (int i=0; i<5; i++) cout << setw(3) << c3[i].value(); cout << endl;

for (int i=0; i<5; i++) cout << setw(3) << c4[i].value(); cout << endl; }

Присваивание объектов

Один объект можно присвоить другому, если они одинакового типа.

Когда один объект А присваивается объекту В, происходит побитовое копирование всех данных-элементов А в данные-элементы В. Данные-элементы объектов А и В приобретают одинаковые значения, при этом объекты остаются совершенно независимыми.

Присваивать можно только объекты одного типа (т.е. с одним именем типа), а не типов одинаковых физически.

Например, в предыдущем примере можно написать:

с1=с2;

Конструктор копирования

Конструктор копирования используется при инициализации объекта существующим объектом.

Инициализация имеет место в трех случаях:

  • когда в операторе объявления один объект используется для инициализации другого: MyClass O1=O2;

  • при передаче объекта в качестве параметра функции: f1(O1);

  • при создании временного объекта для возврата значения из функции:

O2 = f2().

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

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

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

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

Синтаксис конструктора копирования:

имя_класса (const имя_класса &obj)

{ тело_конструктора}

где obj – ссылка на объект, используемый для инициализации другого объекта.

Пример класса, содержащего динамический массив

#include <iostream>

using namespace std;

#include <iomanip>

class array { int *arr; int n;

public: array(int m){arr = new int[m]; n=m;} //конструктор

array (const array &a); //прототип конструктора копирования

~array() {delete []arr;} //деструктор

void put(int i, int v) {if (i>=0 && i<n) arr[i]=v; }

int get(int i) {return arr[i];} };

array::array(const array &a) { int i;

arr = new int [a.n]; //выделение памяти для копии массива

for (i=0; i<a.n; i++) arr[i]=a.arr[i]; } //копирование содержимого

void main (){ int i; array x(5); //вызов обычного конструктора

for (i=0; i<5; i++) x.put(i,i);

array y=x; //вызов конструктора копирования

for (i=0; i<5; i++) cout << setw(3) << y.get(i); }

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

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

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

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

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

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

Можно объявить целый класс дружественным данному классу, включив в определение этого класса описание другого класса с ключевым словом friend. Тогда всем элементам дружественного класса будет разрешен доступ ко всем элементам того класса, для которого он объявлен дружественным:

Class MyCls

{friend void AnotherClass::fun1(int, float);

friend void fun2(char);

friend ThirdClass;}

К друзьям справедливы следующие положения:

  • описания friend не взаимны: если В объявлена другом А, то из этого не следует, что А является другом В;

  • дружественность не наследуется: если В является другом А, то классы, производные от В, не будут автоматически иметь доступ к закрытым элементам А;

  • дружественность не является переходным свойством: если А объявляет другом В, то классы, производные от А, не будут автоматически признавать дружественность В;

  • дружественность не обладает свойством транзитивности: если А объявляет другом В, а В объявляет другом С, то из этого не следует, что С является другом А.

Перегрузка операторов

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

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

.* ?: :: # ## sizeof.

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

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

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

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

Функции-операции

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

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

Функция-операция имеет вид:

тип operator операция (список аргументов)

{ тело функции}

Пример класса

#include <iostream>

using namespace std;

class time {int hour; int minute;

public:

time () {hour = 0; minute = 0;}

time (int h, int m){hour= h; minute=m; }

void Show () { cout << hour << ':' << minute << endl; }

time operator +(time); };

time time::operator +(time t2)

{time tmp; //временный объект для хранения возвращаемого значения

tmp.minute=minute + t2.minute;

if (tmp.minute>=60)

{tmp.minute -=60;

tmp.hour = 1 + hour + t2.hour;

}

else tmp.hour = hour + t2.hour;

return tmp;

}

void main()

{ time t1(12,25), t2(17,50), t3;

t3=t1+t2;

t1.Show(); t2.Show(); t3.Show(); }