Классы. Конструкторы и деструкторы. 


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



ЗНАЕТЕ ЛИ ВЫ?

Классы. Конструкторы и деструкторы.



Классы

Тип данных класс можно определить с помощью конструкции

ключ_класса, имя_класса{ список _членов };

Здесь ключ_класса - одно из служебных слов struct, union, class;

имя_класса - произвольный идентификатор;

список_членов - определения и описания членов класса - данных и функций.

Класс - это набор из одной или более переменных и функций, возможно, различных типов, сгруппированных под одним именем.

Пример структуры - учётная карточка сотрудника, в которой содержится Ф.И.О., адрес, должность, год поступления на работу и т.д. Некоторые из этих атрибутов сами могут оказаться структурами. Так, Ф.И.О. имеет три компоненты, адрес - также несколько компонент.

Класс может иметь имя, иногда называемое тегом. Тег становится именем нового типа в программе. Каждый член класса распознаётся по своему имени, которое должно быть уникальным в данном классе. Члены класса иногда называют его элементами или полями.

Хотя каждому имени члена класса сопоставлен определённый тип, самостоятельным объектом такой член не является. Память выделяется только для конкретного объекта вновь определенного типа в целом.

Введем новые типы FIO и sotrudnik:

struct FIO{ char familia [39],

imya [30],

otchestvo [30] };

struct sotrudnik{ FIO name;

char dolgnost [30];

int year;

float oklad };

Здесь заданы два новых типа структурных переменных и имена этих типов - FIO, sotrudnik. Заметим, что наличие "; " (точки с запятой) после фигурных скобок здесь обязательно.

Теперь можно объявить структурные переменные типа FIO или sotrudnik обычным образом:

FIO name1, name2, name3;

sotrudnik s1, s2, s[50];

Теперь компилятором будет выделена память под переменные name1, name2, name3, s1, s2 и под массив s из пятидесяти структур. Отметим, что число байтов, выделяемое под структурную переменную, не всегда равно сумме длин отдельных членов структуры из-за эффекта выравнивания, производимого компилятором.

Чтобы определить выделенное число байтов, надо воспользоваться операцией sizeof, например, так:

int nf=sizeof (FIO), ns=sizeof (sotrudnik);

После того, как определены структурные переменные, доступ к их членам осуществляется с помощью операции извлечения '.':

a.price c.length d1.dayd3.mon_name s[25].oklads[0].name.familia.

Имена наподобие c.length, d1.dayd3.mon_name, с помощью которых происходит доступ к членам класса, иногда называют уточненными именами. Если определить указатель на структуру, DATE* datep=&d1, то обратиться к члену структуры d1 можно так: (*datep).year, или с помощью операции извлечения из указателя на структуру -> так datep->year, что эквивалентно.

Введем теперь простейший класс "комплексное число":

struct compl{ double real, imag;

void define (double re = 0.0, double im = 0.0){

real = re; imag = im; // задание комплексного числа.

}

void display () {cout << "real = "<< real<< ", imag = " << imag << "\n";}

};

Здесь real, imag - данные-члены или компоненты, а define(), display() - функции-члены или компонентные функции, которые часто называют методами класса.

Теперь можно описать объекты типа compl:

compl a, b, c, *pc = &c;

После этих определений данные-члены структурных переменных доступны в области их видимости:

a.define (3, 7); // Определяется комплексное число 3+7i,

// т.е. a. real = = 3; a.imag = = 7;

b.define (2); // определяется комплексное число 2+0*i = = 2;

c.define (); // комплексное число = = 0;

// оба параметра выбираются по умолчанию.

Данные-члены можно задавать и использовать непосредственно, не через функции define(), display():

a.real = 3; a.imag = 7; (*pc).real = 1; pc->imag = -1;

Здесь данные-члены структуры доступны для использования в программе минуя функции-члены. Можно запретить произвольный доступ к данным. Для этого обычно вместо слова struct в определении класса используют слово class:

class complex { double real, imag;

public:

void display() { cout << " real =" << real;

cout << ", imag =" << imag <<'\n';

}

void define (double re = 0.0, double im = 0.0){

real = re; imag = im;

}

};

Метка public, которая может присутствовать в объявлении класса, в нашем примере делит его тело на две части - "личную", или "собственную" (private) и общую - (public).

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

В определении класса может также явно присутствовать метка private.

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

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

Основное отличие struct и class состоит в уровне доступа по умолчанию. Если нет явного указания уровня доступа, то все члены структуры считаются общими, а класса - собственными. Явное указание уровней доступа делает слова struct и class равнозначными. Обычно использование слова struct вместо class говорит о том, что в ограничении уровня доступа к данным нет необходимости (здесь предполагается, что все члены структуры общие).

Заметим, что типы, созданные программистом с помощью механизма классов, часто называют абстрактными типами данных.

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

В С++ предусмотрены специальные функции-члены класса, которые в большинстве случаев вызываются не программистом, а компилятором и которые предназначены для инициализации объектов абстрактных типов. Такие функции называются конструкторами. Рассмотрим пример:

class cl {

int num;

public:

void set (int i) { num = i; }

void show () { cout <<"Число: " << num <<'\n'; }

};

Чтобы использовать объект такого типа, его надо объявить, инициализировать, а затем уже использовать:

void f(){

cl obj; // Объект создан.

obj.set (10); // Объект инициализирован.

obj.show (); //Объект можно использовать.

}

Теперь используем для инициализации конструктор. Это просто специальная функция - член класса cl, имя которой обязательно совпадает с именем класса:

class cl{int num;

public:

cl (int i) { num = i;} // Конструктор.

void show () { cout << "Число:" << num << '\n';}

};

Заметим, что для конструктора никогда не указывается тип результата!

Функция, использующая этот класс, примет вид:

void f(){

cl obj(10); // Объект создан и инициализирован!

obj.show(); // Здесь объект obj используется!

}

Возможна другая, полная форма записи объявления объекта абстрактного типа, имеющего конструктор: cl obj = cl (10);

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

class cl{ int num;

public:

cl (int i);

void show(){cout <<"Число:" << num <<'\n';}

};

cl::cl(int i) { // Полное, или квалифицированное имя.

num = i;}

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

Деструкторы

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

Это удобно выполнить в деструкторе - функции, которая вызывается для объекта абстрактного типа, когда он выходит из области существования. В рассмотренном выше примере место для хранения строк в памяти выделяется динамически, поэтому полезно определить деструктор. Имя деструктора, как и конструктора, не может быть произвольным, оно образуется символом ~ и именем класса (дополнение к конструктору):

class string {...

public:

~ string () { delete str; }

...

};

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

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

 


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

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

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

Пример:

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

class object {

char *str;

public:

static int num_obj;

object (char *s){ // Конструктор.

str = new char [strlen (s) + 1];

strcpy (str, s);

cout <<"Создается " << str <<'\n'; num_obj ++;

}

~ object (){

cout <<"Уничтожается " << str << '\n';

delete str;

num_obj - -;

}

};

int object::num_obj = 0; // Инициализация. Об этом говорит

// ключевое слово int!

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

Отметим, что классы, определенные внутри функции не могут иметь статических членов.

 



Поделиться:


Последнее изменение этой страницы: 2016-08-15; просмотров: 423; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.139.70.131 (0.031 с.)