pragma once Hard / Занятие 1
.docПонятие класса. Создание простейших классов. Конструкторы и деструкторы
Понятие класса
Набор данных в сочетании с совокупностью операций над ними называется абстрактным типом данных (abstract data type), или АТД. Класс – абстрактный тип данных, определяемый пользователем.
Операции над данными в классах представляются в виде функций. Данные-члены (data members) часто называют полями, а функции-члены (member function) – методами. Поля и методы называются элементами класса.
class имя_класса {
данные-члены класса;
функции-члены класса;
} [список_объектов];
Если список_объектов отсутствует, то объекты объявляются в программе по мере необходимости.
Элементы класса могут быть открытыми и закрытыми. Закрытые элементы класса доступны только для элементов своего класса, открытые – доступны для других частей программы, в которой содержится класс.
class имя_класса {
[private:]
описание скрытых элементов
public:
описание открытых элементов
} ;
Все методы класса имеют доступ ко всем членам класса, в том числе и к закрытым.
Действие любого спецификатора (public, private) распространяется до следующего спецификатора или до конца класса. По умолчанию – private. Можно задавать несколько секций private и publiс.
Пример 1.1. Пример простейшего класса.
#include <iostream>
using namespace std;
class point {
public:
int x, y;
void print_point () {
cout <<'('<<x<<','<<y<<')'<<endl;
}
};
void Prim1_1() {
point a;
a.x=2; a.y=7;
a.print_point();
point b[3];
for (int i=0; i<3; i++){
b[i].x=i; b[i].y=i+2; b[i].print_point();
}
}
int main() {
Prim1_1();
}
Задание. Объясните разницу между структурой и классом:
struct x ( int i, j, k; }; |
class x ( int i, j, k; }; |
Поля могут иметь любой тип, кроме типа этого же класса (но могут быть указателями или ссылками на этот же класс).
Инициализация полей при описании не допускается. В каждом классе есть хотя бы один метод, имя которого совпадает с именем класса (конструктор). Он вызывается автоматически при создании объекта класса и предназначен для инициализации объекта.
Тип возвращаемого значения в определении конструктора не указывается.
Методы класса могут быть как определены в классе, так и объявлены (приведены только заголовки).
Если тело метода определено внутри класса, он является встроенным.
Если метод только объявлен внутри класса, то его нужно определить в другом месте программы с помощью операции доступа к области видимости «::»:
тип имя_класса::имя_метода (параметры) {
/* тело метода */ }
Чтобы создать объект (экземпляр класса) нужно объявить в программе переменную типа «класс».
Каждый объект имеет собственные копии полей, но методы у них общие.
Если поле описано как статическое (static), то оно существует в единственном экземпляре (общее для всех объектов класса).
Статические методы предназначены для обращения к статическим полям. Они могут обращаться только к статическим полям и вызывать другие статические методы класса.
После создания объекта можно обращаться к открытым элементам класса, используя операцию точка.
class point {
public:
int x, y; //поля
void print_point () { //метод
cout <<'('<<x<<','<<y<<')'<<endl;
}
point(){x=1; y=1;}//конструктор по умолчанию
//объявление конструктора с параметрами
point(int x1,int y1){x=x1; y=y1;}
void move(int dx, int dy); //объявление метода
};
void point::move(int dx, int dy){x+=dx; y+=dy;} //определение метода
void Prim1_1() {
point a; a.print_point();
a.x=2; a.y=7;
a.print_point();
point b[3];
for (int i=0; i<3; i++){
b[i].x=i; b[i].y=i+2; b[i].print_point();
}
point c(-5,2); c.print_point();
c.move(5,5); c.print_point();
}
Пример 1.2.
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; }
Конструктор – это функция-элемент класса, автоматически выполняющаяся в момент создания объекта.
Имя конструктора совпадает с именем класса. Конструкторы можно перегружать.
Свойства конструктора:
-
не указывается тип возвращаемого значения;
-
не может возвращать значение;
-
не наследуется.
Необходимость использования конструкторов вызвана тем, что элементы класса не могут получать начальные значения в определении класса другим способом.
Если конструктор не определен программистом, то он создается компилятором как функция без параметров и с пустым телом.
Деструктор – это функция-элемент класса, автоматически выполняющаяся при удалении объекта (функция, обратная конструктору). Деструктор не уничтожает объект, а только выполняет подготовительные действия.
Имя деструктора совпадает с именем класса, но имеет префикс «~» (тильда).
Деструктор не имеет аргументов и не может возвращать значение, поэтому в классе он всегда один.
Если деструктор не объявлен явно, он создается компилятором как пустая функция.
Один объект можно присвоить другому, если они одинакового типа.
Когда один объект А присваивается объекту В, происходит побитовое копирование всех данных-элементов А в данные-элементы В. Данные-элементы объектов А и В приобретают одинаковые значения, при этом объекты остаются совершенно независимыми.
Присваивать можно только объекты одного типа (т.е. с одним именем типа), а не типов одинаковых физически.
Например, в предыдущем примере можно написать:
a=b;
Конструктор копирования используется при инициализации объекта существующим объектом.
Инициализация имеет место в трех случаях:
-
когда в операторе объявления один объект используется для инициализации другого: MyClass O1=O2;
-
при передаче объекта в качестве параметра функции: f1(O1);
-
при создании временного объекта для возврата значения из функции:
O2 = f2().
Конструктор копирования никогда не используется при присваивании.
Конструктор копирования, заданный по умолчанию, выполняет поэлементное копирование нестатических элементов. При этом выполняется побитовое копирование.
Если в классе есть динамический массив, то копируется только указатель, а не элементы. После выполнения delete второй указатель будет не определен.
Синтаксис конструктора копирования:
имя_класса (const имя_класса &obj)
{ тело_конструктора}
где obj – ссылка на объект, используемый для инициализации другого объекта.
Пример 1.3. Пример класса, содержащего динамический массив
#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); }
Задание: создайте класс «прямоугольник» с полями «высота» и «ширина» и методами «площадь» и «периметр». В классе должны быть 2 конструктора: с параметрами для инициализации полей и по умолчанию (инициализация полей единицами).