Автоматическая инициализация — КиберПедия 

Индивидуальные очистные сооружения: К классу индивидуальных очистных сооружений относят сооружения, пропускная способность которых...

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

Автоматическая инициализация

2020-05-08 197
Автоматическая инициализация 0.00 из 5.00 0 оценок
Заказать работу

Когда создается объект типа Counter, нам хотелось бы, чтобы его поле count было инициализировано нулевым значением, поскольку большинство счетчиков на­чинают отсчет именно с нуля. Мы могли бы провести инициализацию с помо­щью вызова функции set_count() с аргументом, равным нулю, или создать специ­альный метод zero_count(), обнуляющий значение функции. Недостаток такого подхода заключается в том, что эти функции необходимо вызывать явно каждый раз при создании объекта типа Counter:

Counter cl: // при определении объекта

cl.zero_count(): // это необходимое действие

Подобные действия легко могут привести к неправильной работе всей про­граммы, поскольку программисту для этого достаточно забыть проинициализировать хотя бы одну переменную после ее создания. Если в программе создается множество таких переменных, гораздо проще и надежнее было бы инициализи­ровать их автоматически при создании. В нашем примере конструктор Counter() выполняет эти действия. Конструктор вызывается автоматически при создании каждого из объектов. Таким образом, в функции mainQ оператор

Counter cl. с2:

создает два объекта типа Counter. При создании каждого из них вызывается конст­руктор Counter(), присваивающий полю counter нулевое значение. Таким образом, кроме создания переменных, данный оператор еще присваивает их полям нулевое значение.

Инициализаторы в конструкторах

Главной задачей конструктора класса является инициализация данных созда­ваемых им объектов. Однако производить инициализацию данных при по­мощи оператора присваисания в теле конструктора не рекомендуется.

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

Порядок следования идентификаторов в списке инициализации не имеет зна­чения.

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

count()

{ count =0; }

Такая форма записи не рекомендуется, несмотря на то, что она не содержит ошибок. Инициализация в нашем примере происходит следующим образом:

count(): count(0)

{ }

Инициализация расположена между прототипом метода и телом функции и предварена двоеточием. Инициализирующее значение помещено в скобках пос­ле имени поля.

Если необходимо инициализировать сразу несколько полей класса, то значе­ния разделяются запятыми, и в результате образуется список инициализации:

someClass (): m1(7), m2(33), m2(4) { }

Результаты работы программы со счетчиком

В функции main() рассматриваемой нами программы создаются два объекта класса Counter с именами cl и с2. Затем на экран выводятся значения полей каж­дого из объектов, которые, согласно нашей задумке, должны быть инициализи­рованы нулевыми значениями. Далее значение счетчика cl инкрементируется один раз, а значение счетчика с2 — два раза, и программа вновь заставляет объек­ты вывести значения своих полей на экран (что является в данном случае вполне корректным). Результат работы программы выглядит следующим образом:

cl=0

с2=0

cl=1

с2=2

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

counter(): count(0)

{ cout << "Конструктор\n": }

Теперь результат работы программы будет выглядеть следующим образом:

Конструктор

Конструктор

cl=0

с2=0

cl=1

с2=2

Как можно видеть, конструктор исполняется дважды: первый раз — для переменной cl, второй раз — для переменной с2, во время выполнения оператора

counter cl, с2; в функции main().

 

Конструктор по умолчанию

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

Объявление конструктора по умолчанию имеет следующий формат:

public:имя_класса ();

Например, для класса своок прототип конструктора по умолчанию записыва­ется со спецификатором открытого доступа

public: CBook ();

 

Пример реализации конструктора по умолчанию   ]

СВоок:: СВоок (): m_year (0), m_pTitle ("")

{   m_author [ 0 ] = ‘\0'; }

 

В результате работы этого конструктора будет построен объект-книга, у которого данное year получит нулевое значение, массив author нач­нется с нулевого байта точно так же, как и название книги, на которое указы­вает pTitie. Для инициализации автора не может быть использован инициа­лизатор, так как этот член-данное объявлен в классе как символьный массив.

 

Конструктор с параметрами

Конструктор с параметрами инициализирует значения данных объекта зна­чениями полученных параметров. Параметров будет столько, сколько данных необходимо проинициализировать. Прототип такого конструктора имеет формат:

public:имя_класса (список формальных параметров);

Для класса CBook конструктор с параметрами может иметь следующий прото­тип: CBook (char*, char*, int);

 

Пример реализации конструктора с параметрами     

СВоок:: СВоок (char *author, char *title, int year)

: m_уеаг (year), m_pTitle (title)

{

strncpy_s (m_author, 50, author, 49);

if (strlen (author) > 49) m_author [ 49 ] = '\0';

}

 

В результате работы этого конструктора будет построен объект-книга, у которого данное щ_уеаг получит значение параметра year, в массив m_author будет скопировано не более 49 байтов из строки author, и указатель m_pTitie будет содержать адрес, по которому скопировано значение title.

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

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

public:имя_класса (имя_класса &);

Для класса CBook конструктор копирования объявляется в спецификации класса со следующим прототипом:

СВоок (СВоок &);

 

Листинг 14.6. Пример конструктора копирования       

СВоок:: СВоок (СВоок &о): m_year (o. m_year) {

strcpy_s (m_author, strlen (o.m_author) + 1, o.m_author);

m_pTitle = new char [strlen (o.m_pTitle) + 1 ];

strcpy_s (m_pTitle, strlen (o. m_pTitle) + 1, o. m_pTitle);

}

 

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

Програм­ма EC0PYC0N демонстрирует использование копирующего конструктора по умол­чанию:

 // есорусо n.срр

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

#include <iostream>

using namespace std;

//////////////////////////////////////////////////////////

class Distance // длина в английской системе

{

private:

int feet;

float inches;

public:

// конструктор без аргументов

Distance(): feet(0), inches(0.0) { }

// конструктора с одним аргументом нет!

// конструктор с двумя аргументами

Distance(int ft, float in): feet(ft), inches(in) { }

void getdist()  // ввод длины пользователем

{

cout << "\nВведите число футов ";

cin >> feet;

cout << "Введите число дюймов: ";

cin >> inches;

}

void showdist() // вывод длины

{ cout << feet << "\'-" << inches << "'\'"; }

};

//////////////////////////////////////////////////////////

int main()

{

Distance dist1(11,6.25); // конструктор с двумя аргументами

Distance dist2(dist1); // два конструктора с одним аргументом

Distance dist3 = dist1;

// вывод всех длин

cout <<"\ndistl - ";

dist1.showdist();

cout <<"\ndist2 - ";

dist2.showdist();

cout <<"\ndist3 - ";

dist3.showdist();

cout << endl;

return 0;

}

Мы инициализировали объект distl значением 11’-6.25" при помощи конст­руктора с двумя аргументами. Затем мы определяем еще два объекта класса Distance с именами dist2 и dist3, оба из которых инициализируются значением объекта distl. Возможно, вам покажется, что в данном случае должен был вы­зваться конструктор с одним аргументом, но поскольку аргументом являлся объект того же класса, что и инициализируемые объекты, были предприняты иные действия. В обоих случаях был вызван копирующий конструктор по умол­чанию. Объект dist2 инициализирован при помощи оператора

Distance dist2(distl):

Действие копирующего конструктора по умолчанию сводится к копирова­нию значений полей объекта distl в соответствующие поля объекта dist2. Как это ни удивительно, но идентичные действия для пары объектов distl и dist3 вы­полняются при помощи оператора

Distance dist3 = distl;

Можно подумать, что данный оператор выполняет операцию присваивания, но это не так. Здесь, как и в предыдущем случае, вызывается конструктор копи­рования по умолчанию. Оба оператора выполняют одинаковые действия и рав­ноправны в использовании. Результат работы программы выглядит следующим образом:

distl = 11'-6.25"

dist2 = 11"-6.25"

dist3 -=11'-6.25"

Видим, что объекты dist2 и dist3 действительно имеют те же значения, что и объект distl. В главе 11 «Виртуальные функции» мы расскажем, каким образом можно создать свой собственный копирующий конструктор с помощью пере­грузки копирующего конструктора по умолчанию.

 

 

Деструктор

Деструктор (destructor) — специальный метод класса, используемый для разрушения объектов класса. Имя деструктора совпадает с именем конструк­тора (именем класса), которому предшествует символ тильда ~. Он всегда имеет открытый спецификатор доступа и не имеет ни типа, ни параметров. Деструктор управляет уничтожением объекта из оперативной памяти.

Вызывается деструктор автоматически при разрушении объекта. Если объект создавался динамически через указатель при помощи оператора new, то для уничтожения такого объекта следует использовать оператор delete для ука­зателя.

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

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

Объявление деструктора имеет следующий формат:

public:~имя_класса ();

Например, для класса своок прототип деструктора в спецификации класса имеет вид:

~СВоок ();

 

СВоок:: ~СВоок () {delete [ ] m_pTitle; }

 

Результатом действия деструктора ~СВоок () является освобождение блока памяти с начальным адресом из itLpTitle, выделенного ранее конструктором класса.

 


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

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

Адаптации растений и животных к жизни в горах: Большое значение для жизни организмов в горах имеют степень расчленения, крутизна и экспозиционные различия склонов...

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

История развития хранилищ для нефти: Первые склады нефти появились в XVII веке. Они представляли собой землянные ямы-амбара глубиной 4…5 м...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.048 с.