Элементы класса секция private Секций м.б. несколько

Лекция 8.

Классы.

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

Данные класса – их еще называют полями (сравнить со структурой) – это характеристики объекта.

Функции класса – методы (функции – члены класса)описывают действия над данными, эти функции-члены предназначены для доступа к данным.

В простейшем случае описание класса выглядит так:

class имя

{private:

//элементы класса секция private Секций м.б. несколько,

. . . . . . . . . . . . . . . . порядок их не важен.

public:

//элементы класса секция public

. . . . . . . . . . . . . .

};

private и public –это спецификаторы доступа, они управляют видимостью элементов класса. После privateстоятэлементы, видимые внутри класса. Этот вид доступа принят в классах по умолчанию. Доступ к этим элементам возможен только из функций, расположенных внутри класса, т.е. это возможность защиты этих элементов от доступа функций, расположенных вне класса.

В секции public описываются данные и функции, которые доступны вне класса (это интерфейс класса).

Итак, основополагающей идеей ООП является объединение данных и действий (функций), производимых над этими данными, в одном классе. Говорят : данные и методы инкапсулированы.

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

class myclass

{ private:

int dan; // поля могут быть любого типа, кроме типа

char c; //этого класса, но м.б. указателями или ссылками

public: //на этот класс. Инициализация полей не допускается

void show(){cout<<dan<<’ ’<<c<<endl;}

int get_dan(){return dan;}

char get_c() {return c;}

};

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

Определение объектов: Объект – это переменная типа класс.

myclass a1,a2;

myclass x[10];

myclass *pw;

myclass *qw=new myclass(65,’A’);

myclass &t=a1;

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

x[3]. show();

a1.show(); ‘ .’ –операция доступа к члену класса через имя объекта, отобразит на экране значения полей этого объекта.

При обращении через указатель операцию ‘->’ можно выбрать:

cout<<qw->get_dan(); cout<<(*qw).get_dan();

Замечание.В некоторых языках ООП вызовы методов называют сообщениями(посылка сообщения объекту a1 с указанием вывести данные на экран).

Можно при описании класса определить функцию, которая будет задавать значения полей класса:

void set_dan (int d) {dan=d;}

void set_c (char ch) {c=ch;}

a1.set_dan (65); a1.set_c (‘A’);

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

Конструктор отличается от других методов класса:

а) имя конструктора совпадает с именем класса;

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

Есть 3 вида конструкторов:

1)При создании объекта специальный конструктор инициализирует поля объекта нулями. Такой конструктор называется конструктор по умолчанию

Если в классе конструктор по умолчанию не объявлен, то компилятор создает его сам. Без него нельзя было бы определить переменные типа класс: myclass a1;

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

2) Если необходимо инициализировать какие-то поля конкретными значениями, то необходимо объявить конструктор для инициализации .Их может быть несколько.

myclass a (69,’D’);

3)третий способ инициализации объекта – когда используется уже существующий объект, это конструктор копированияОнимеет единственный параметр – ссылку на объект этого же класса:

myclass (myclass & x) - конструктор копирования. Он вызывается:

(1)при описании объекта с инициализацией другим объектом:

myclass a2 (a1); //a1 определен ранее.

myclass a2 =a1; // это инициализация, а не присваивание.

(2) при передаче объекта в функцию по значению.

(3) при возврате объекта из функции.

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

myclass b(a);

либо myclass с=a; //это не присваивание, здесь вызывается конструктор копирования по умолчанию.

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

 

Деструктор –вид метода, который используется для освобождения памяти, занятой объектом, при выходе из области действия объекта. Вид деструктора:

~ имя_класса () {};

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

 

Деструктор вызывается автоматически. Его иногда можно и не описывать. Но деструктор должен быть описан, если в объекте (в классе) есть указатель на память, выделенную динамически.

Замечание. struct является классом, отличие её – все поля у неё по умолчанию являются полями типа public,т.е. они все доступны.

Пример класса:Обыкновенная дробь p/q. Опишем 3-х файловый проект, но не сразу весь, а частями (слоями)

// fraction.h – интерфейсный файл класса

1)#include <iostream>

2)#include <fstream>

Using namespace std;

4)class frac // дробь p/q

5) { private:

6) int p; //числитель

7) unsigned int q; //знаменатель

8) public:

9) frac (); //конструктор по умолчанию

10) frac( int a, unsigned int b); //конструктор инициализации

11) frac (const frac & c); // конструктор копирования

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

12) ~frac() ; // деструктор

// методы

Int getp() const;

Unsigned int getq() const ;

Константный метод объявляется с ключевым словом const после списка параметров, он не может изменять значения полей класса, может вызывать только константные методы, но его можно вызывать для любых объектов.

Void setp(int a);

Void setq(unsigned int b);

Void show()const;

_ Здесь пока заканчивается 1-ая часть fraction.h______________   //fractionR.cpp – Файл реализации

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

9)frac :: frac () : p(0), q(1) {fout<<"frac()={"<<p<<'/'<<q<<"}"<<endl; }

 

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

10)frac::frac (int a, unsigned int b): p(a), q(b)

{ reduce(); fout<<"frac (int a, unsigned int b)"<<endl;

if (q==0){fout<<" denominator 'q' is zero!"<<endl; exit(5); }}

11) frac::frac(const frac & c) : p(c.p), q(c.q )

{fout<<"frac(const frac&["<<c<<"])={"<<p<<'/'<<q<<"}"<<endl; }

 

12)frac::~frac() // деструктор

{ fout<<"Destructor ~frac() for {"<<p<<'/'<<q<<"}"<<endl; }

 

13)int frac::getp()const{return p;}

14)unsigned int frac::getq() const{return q;}

 

void frac::setp(int a){p=a;}

void frac::setq(unsigned int b)

{ if (b!=0){q=b;}

else {fout<<"Cann't divide by zero: denominator 'q' is zero!"<<endl; exit(5);}}

 

15)void frac::show() const

{ fout<<"{"<<getp()<<'/'<<getq()<<"}"<<endl;

fout<<"show()"<<endl;}

16)frac frac::reduce ()

{ unsigned int s0;

unsigned int s1=abs(p);

fout<<"Do reduce()..."<<endl;

unsigned int s2=q;

while (s2>0)

{ s0=s1;

s1=s2;

s2=s0%s1;}

p=p/int(s1);

q=q/s1;

fout<<"Reduce()={"<<p<<'/'<<q<<"}"<<endl;

return *this;

}

Указатель this.

// fractiongl.cpp 3-ий файл Главная программа #include "fraction.h" ofstream fout;

Frac operator -();

frac operator *(frac &); frac operator / (frac &)  

Using namespace std;

Class VEC

double *v; // указатель на вектор int ne; // длина вектора public:

Extern ofstream fo;

{fo<<"VEC() n"; } VEC::VEC(int n) : ne(n), v(new double[n]) {fo<<"cst1 "<<this<<' '<<v<<endl;}

Return z;

}

 

//MyMasDinGlav.cpp

#include "MyDinMasHead.h"

ofstream fo("output.txt");

Void main()

{fo<<"out vectm2"<<endl<<endl;

fo<<"VEC x"<<endl;

VEC x;

Int i;

VEC a(5),b(5),c(5),d(5),e(7),f(7);

for(i=0;i<7;i++)e[i]=i; fo<<"a:"<<endl; for(i=0;i<5;i++)

Return z;

}

 

//MyMasDinGlav.cpp

#include "MyDinMasHead.h"

ofstream fo("output1.txt");

Void main()

{fo<<"out vectm2"<<endl<<endl;

fo<<"VEC x"<<endl;

VEC x;

Int i;

VEC a(5),b(5),c(5),d(5),e(7),f(7);

for(i=0;i<7;i++)e[i]=i; fo<<"a:"<<endl; for(i=0;i<5;i++)

VEC r(a);

f= a+e;

for(i=0;i<7;i++){ fo<<f[i]<<' ';}

fo<<endl;

fo<<"x=a"<<endl;

x=a;

fo<<"x:"<<endl;

for(i=0;i<5;i++)

{ fo<<x[i]<<' ';

}

 

 

out vectm1

VEC x

VEC()

Cst1 0012FF34 00365710

Cst1 0012FF24 00366D20

Cst1 0012FF14 00366D78

Cst1 0012FF04 00366EF8

Cst1 0012FEF4 00366F50

Cst1 0012FEE4 00366FB8

a:

0 1 2 3 4

VEC::operator=(VEC& y)0012FF50 00000000

x=a=b;

VEC::operator=(VEC& y)0012FF34 00365710

VEC::operator=(VEC& y)0012FF50 00367020

b:

1 2 3 4 5

VEC::operator+(VEC& y)0012FF34 0012FF24

VEC z(nm);0012FF34 0012FF24

Cst1 0012FD30 00367078

VEC::operator=(VEC& y)0012FD30 00367078

VEC(VEC& a)-cst20012FDC4 003670D0

VEC::operator+(VEC& y)0012FDC4 0012FF14

VEC z(nm);0012FDC4 0012FF14

Cst1 0012FD38 00367078

VEC::operator=(VEC& y)0012FD38 00367078

VEC(VEC& a)-cst20012FDD4 00367128

VEC::operator+(VEC& y)0012FDD4 0012FF04

VEC z(nm);0012FDD4 0012FF04

Cst1 0012FD40 00367078

VEC::operator=(VEC& y)0012FD40 00367078

VEC(VEC& a)-cst20012FDE4 00367180

VEC::operator=(VEC& y)0012FF04 00366EF8

d:

2 6 10 14 18

c:

0 2 4 6 8 VEC::operator+(VEC& y)0012FF04 0012FF14

VEC z(nm);0012FF04 0012FF14

Cst1 0012FD40 00367078

VEC::operator=(VEC& y)0012FD40 00367078

VEC(VEC& a)-cst20012FDF4 003670D0

VEC::operator=(VEC& y)0012FF04 00366EF8

d=d+c:

2 8 14 20 26

VEC(VEC& a)-cst20012FED4 00367078

VEC::operator+(VEC& y)0012FF34 0012FEF4

VEC z(nm);0012FF34 0012FEF4

Cst1 0012FD40 003670D0

VEC::operator=(VEC& y)0012FD40 003670D0

VEC(VEC& a)-cst20012FE04 00367138

VEC::operator=(VEC& y)0012FEE4 00366FB8

1 3 5 7 9 5 6

x=a

VEC::operator=(VEC& y)0012FF50 00367020

x:

1 2 3 4 5

VEC::operator=(VEC& y)0012FF34 003556A8

VEC::operator=(VEC& y)0012FF50 00356FB8

b:

1 2 3 4 5

Cst1 0012FD30 00357010

VEC::operator=(VEC& y)0012FD30 00357010

VEC(VEC& a)-cst20012FDC4 00357068

Cst1 0012FD38 00357010

VEC::operator=(VEC& y)0012FD38 00357010

VEC(VEC& a)-cst20012FDD4 003570C0

Cst1 0012FD40 00357010

VEC::operator=(VEC& y)0012FD40 00357010

VEC(VEC& a)-cst20012FDE4 00357118

VEC::operator=(VEC& y)0012FF04 00356E90

d:

2 6 10 14 18

c:

Cst1 0012FD40 00357010

VEC::operator=(VEC& y)0012FD40 00357010

VEC(VEC& a)-cst20012FDF4 00357068

VEC::operator=(VEC& y)0012FF04 00356E90

d=d+c:

2 8 14 20 26

VEC(VEC& a)-cst20012FED4 00357010

Cst1 0012FD40 00357068

VEC::operator=(VEC& y)0012FD40 00357068

VEC(VEC& a)-cst20012FE04 003570D0

VEC::operator=(VEC& y)0012FEE4 00356F50

1 3 5 7 9 5 6

x=a

VEC::operator=(VEC& y)0012FF50 00356FB8

x:

1 2 3 4 5