Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C _Учебник_МОНУ

.pdf
Скачиваний:
206
Добавлен:
12.05.2015
Размер:
11.12 Mб
Скачать

Об’єктно-орієнтоване програмування

509

 

 

тить такі методи: конструктор за замовчуванням, конструктор з двома параметрами; podatok() – метод який обчислює податок працівника за встановленим правилом; zarplatnia() – метод який обчислює “чисту” зарплатню працівника.

Примітка. Якщо серед методів класу є такі, що мають тип AnsiString, наприклад,

AnsiString info()

{ return " Зарплатня =" + FloatToStr(zarplatnia()); }

тоді першою у файлі необхідно записати директиву

#include <vcl.h>

Запишемо у файлі Рrac.cpp визначення (реалізацію) методів класу podatok() та zarplatnia() (після всіх стандартних директив файла):

Файл Рrac.cpp

#pragma hdrstop

#include "Рrac.h" // Автоматичне долучення файлів визначення класу // Реалізація методу обчислювання податку

double pracivnik::podatok()

{double nal; switch(vid)

{case 0: if(oklad<=300) nal=0; else nal=oklad*0.15; break; case 1: nal=oklad*0.2;

}

return nal;

}

// Реалізація методу обчислювання зарплатні double pracivnik::zarplatnia()

{ return oklad - podatok();

}

Запишемо у головному файлі проекту Unit1.cpp код програми для кнопки “Обчислити” та долучимо до нього файл визначення класу Prac.h.

Головний файл проекту Unit1.cpp

#include <vcl.h>

// Долучення файла оголошення та визначення методів класу

#include "Prac.h"

#pragma hdrstop #include "Unit1.h"

//--------------------------------------------------------

#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1;

//-------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)

{

}

// Оголошення структури типу черга
// Оголошення класу

510

Розділ 14

 

 

//--------- Відгук на кнопку «Обчислити» --------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{int k;

if(RadioGrooup1->ItemIndex == 0) k=0; else k=1;

pracivnik a(StrToFloat(Edit1->Text), k); // Створення об‟єкта a

Edit2->Text = FloatToStr(a.podatok()); Edit3->Text = FloatToStr(a.zarplatnia());

}

У програмному коді для події OnClick кнопки “Обчислити” оголошено змінну об‟єкта класу a, поля якої задаються за допомогою конструктора з двома параметрами. Для цього об‟єкта викликатимуться методи podatok() та zarplatnia(), а їхні результати виводитимуться до текстових полів.

На формі розташовано, окрім текстових полів (компонентів Edit) для введення значення окладу певного працівника та виведення результатів, ще й компонент RadioGroup для обирання виду діяльності (значення поля vid).

Можливі варіанти робочого вигляду форми при виконанні проекту:

Приклад 14.3. Створити клас для динамічної структури, яку називають черга. Структура містить два інформаційні поля: прізвище студента і екзаменаційний бал з інформатики. Клас матиме такі методи: конструктор, долучення елемента до черги, вилучення елемента з черги, переглядання елементів черги.

Текст програми: structlistec

{AnsiString Fio; int num; listec *next;

};

class queue { private:

listec *curr,*first,*last; // Поля класу – вказівники на поточний, // перший та останній елементи класу

public:

queue(){curr=first=last=NULL;} // Конструктор класу

void add(String fio, int d); // Долучення елементів до черги

Об’єктно-орієнтоване програмування

511

 

 

 

 

void del();

 

// Вилучення елемента з черги

 

AnsiString view();

// Переглядання змісту черги

 

};

 

 

 

// Реалізація функції долучення елемента до черги

 

void queue::add(String fio,int d)

 

{ curr=new listec;

// Виділення пам‟яті під новий елемент черги

 

curr->Fio=fio;

// Занесення до нового елемента прізвища

 

curr->num=d;

// Занесення до нового елемента значення балу

 

curr->next=0; // Після нового елемента інших елементів покищо немає

 

if (first==0)

// Якщо черги ще нема,

 

first=curr;

// то новий елемент стає першим,

 

else

// інакше елемент долучається після останнього,

 

last->next=curr;

// записуючи в last адресу нового елемента

 

last=curr;

// Тепер новий елемент стає останнім

 

}

 

 

 

// Реалізація функції вилучення першого елемента з черги

 

void queue::del()

 

 

 

{ curr=first;

 

 

 

if (first==0)

// Якщо черга є порожня,

 

{ ShowMessage("Черга порожня!"); // виводиться повідомлення

 

return;

// і виконання переривається

 

}

 

 

 

first=first->next;// first указує на наступний елемент

 

delete curr;

// Знищення елемента, який вилучається

 

}

// Реалізація функції переглядання елементів черги

AnsiString queue::view()

{AnsiString s=""; if (curr==0)

{ShowMessage("Черга порожня!"); s=""; return s; } while (curr!=0)

{s=s+curr->Fio+" "+IntToStr(curr->num)+"\r\n";

curr=curr->next;

}

return s;

}

queue stt; // Створення об‟єкта класу

// Кнопка долучання до черги нового елемента (інформації про студента) void __fastcall TForm1::Button1Click(TObject *Sender)

{String fio=Edit1->Text;

int d=StrToInt(Edit2->Text); stt.add(fio,d); Edit1->Text="";

Edit2->Text=""; Edit1->SetFocus();

}

512

Розділ 14

 

 

// Кнопка переглядання даних черги (інформації про студентів)

void __fastcall TForm1::Button2Click(TObject *Sender)

{Memo1->Clear(); Memo1->Lines->Add(stt.view());

}

// Кнопка вилучання елемента (інформації про студента) з черги void __fastcall TForm1::Button3Click(TObject *Sender) { stt.del();

}

Форма з результатами роботи програми:

14.6 Деструктори

Деструктор – це особлива форма методу класу, який застосовується для звільнення пам‟яті, зайнятої об‟єктом. Деструктор за суттю є антиподом конструктора. Якщо конструктор – це функція, яка допомагає будувати (конструювати) об‟єкт, то деструктор являє собою функцію, яка допомагає знищувати об‟єкт, тобто звільняти від нього пам‟ять. Деструктор викликається автоматично, коли об‟єкт виходить за межі області видимості.

Деструктор при визначенні класу має такий формат:

~ <ім‟я класу> () { <оператори деструктора> }

Розглянемо основні властивості деструктора.

Ім‟я деструктора розпочинається з тільди (~), безпосередньо за якою йде ім‟я класу.

Деструктор – це метод, який виконується автоматично.

Конструктор не повертає жодного значення, навіть типу void.

Деструктор не має аргументів.

Вказівник на деструктор визначити не можна.

Деструктор не успадковується.

Якщо деструктор явно не визначено, компілятор автоматично ство-

рює порожній деструктор.

По завершенні програми об‟єкти усіх класів знищуються з пам‟яті комп‟ютера навіть тоді, коли деструктор явно не визначено.

// Приховані поля класу

Об’єктно-орієнтоване програмування

513

 

 

У попередніх програмах об‟єкти створювалися після їхнього оголошення. По завершенні програми C++ автоматично викликав деструктор для кожного об‟єкта, хоча його не було явно визначено у програмі.

Деструктор, окрім деініціалізації об‟єктів, може виконувати деякі дії, наприклад, виведення остаточних значень елементів даних класу, що буває зручно при налагодженні програми. Як приклад, визначимо клас worker з деструктором та конструктором:

class worker

{ private:

char name[64] ; long worker_id; float salary;

public: // Загальнодоступні методи класу worker(char *iname, long іworker_id, float isalary); // конструктор

void ~worker(void); // Деструктор

void show_worker(void); // Функція виведення інформації

};

Реалізація деструктора для класу worker (поза класом):

void worker::~worker(void)

{ cout << "Знищення об’єкта для " << name << endl; }

Цей деструктор у консольному режимі виведе на екран значення елемента класу name та повідомлення про те, що C++ знищує цей об‟єкт. Наприклад, створимо об‟єкт для визначеного вище класу:

void main(void)

{ worker worker("Василенко", 777, 10101.0); worker.show_worker();

}

У результаті виконання цієї програми на екрані побачимо:

Прізвище: Василенко Код робітника: 777 Зарплатня: 10101.00

Знищення об’єкта для Василенко

Явно розміщувати деструктор у класі треба у разі, якщо об‟єкт містить вказівники на пам‟ять, виділену динамічно, – інакше при знищуванні об‟єкта пам‟ять, на яку посилались його поля-вказівники, не буде позначено як звільнену.

сlass CMyClass

{ public:

CMyClass();

//Конструктор класу CMyClass

~CMyClass();

//Деструктор класу CMyClass

private:

 

int MyInt;

//Змінна типу int (ціле число)

int *point;

//Змінна типу вказівник на int (ціле число)

};

 

514

Розділ 14

 

 

CMyClass::CMyClass()//Конструктор

{ MyInt = 10;

//На етапі ініціалізації об‟єкта класу CMyClass

 

//присвоюється змінній цього об‟єкта MyInt значення 10

point = new int;

//Виділення пам‟яті під ціле число для вказівника

*point = 20;

//Записування у виділену пам‟ять числа 20

}

 

CMyClass::~CMyClass()// Деструктор

{ MyInt = 0; // Об‟єкт класу CMyClass фактично припинив своє існування, // але надамо змінній класу MyInt значення 0

delete point; // Використаємо вказівник на число для того,

//щоби звільнити пам‟ять, яку виділено під це число

//(Автоматично деструктор не виконує цього!)

}

Приклад 14.4 Створимо клас – “два резистори, які з‟єднані паралельно” з полями номіналів r1 та r2 (див. приклад 4.7). Крім того, явно визначимо деструктор в оголошенні класу та обчислимо сумісний опір цих резисторів.

Розв‟язок. У програмі використовуватимемо різні способи визначення конструкторів: без параметрів (конструктор 1), з одним (конструктор 2) та з двома параметрами (конструктор 3). Програму розмістимо в двох файлах Unit1.h та Unit1.cpp, призначення операторів пояснюватимемо коментарями.

Файл Unit1.h

// Оголошення класу

 

 

class resistor

// Клас – два паралельних резистора

{ private:

 

 

float r1,r2;

// Поля класу – значення номіналів резисторів

public:

 

 

resistor(float iR1):r1(iR1),r2(1e9) {}

// Конструктор 1

resistor():r1(1e9),r2(20) {}

// Конструктор 2

resistor(float iR1,float iR2):r1(iR1),r2(iR2){};//Конструктор 3 float comr(); // Метод класу – обчислення сумісного опору двох резисторів

AnsiString resistor::Info();// Метод класу – формування рядка

// зі значеннями номіналів резисторів

~ resistor(void); // Деструктор };

// Опис реалізації функцій (методів) класу float resistor::comr()

{ return r1*r2/(r1+r2); }

AnsiString resistor::Info()

{ return "r1="+FloatToStr(r1)+" r2="+FloatToStr(r2); }

resistor::~ resistor(void) // Реалізація деструктора

{ Form1->Memo1->Lines->Add("Об’єкт знищено ("+ Info()+")"); }

Об’єктно-орієнтоване програмування

515

 

 

 

 

Файл Unit1. cpp

 

 

 

//--------- Відгук на кнопку «Об‟єкти класу» --------------

 

void __fastcall TForm1::Button1Click(TObject *Sender)

 

{ resistor a11;

// Створення об‟єкта класу a11 конструктором 1

float ra1=a11.comr(); // Обчислення сумісного опору для об‟єкта a11

 

// Виведення результатів для об‟єкта a11

 

 

Memo1->Lines->Add(a11.Info()+"

r_a11="+FloatToStr(ra1));

 

a11.~ resistor();

// Знищення об‟єкта a11 деструктором

 

resistor a12(40);

// Створення об‟єкта класу a12 конструктором 2

float ra2=a12.comr(); // Обчислення сумісного опору для об‟єкта a12

 

// Виведення результатів для об‟єкта a12

 

 

Memo1->Lines->Add(a12.Info()+"

r_a12="+FloatToStr(ra2));

 

resistor a13(20,20);

// Створення об‟єкта класу a13 конструктором 3

float ra3=a13.comr(); // Обчислення сумісного опору для об‟єкта a13

 

// Виведення результатів для об‟єкта a13

 

 

Memo1->Lines->Add(a13.Info()+"

r_a13="+FloatToStr(ra3));

 

}

 

 

 

Результати роботи програми – значення загального опору двох паралельних резисторів для трьох об‟єктів, створених за різними конструкторами та з явним використанням деструктора, – наведено на зображенні форми проекту:

Як бачимо, після роботи з першим об‟єктом (a11) викликається функ- ція-деструктор, яка знищує об‟єкт та виводить повідомлення про цю дію. Наприкінці програми деструктор автоматично звільнює пам‟ять від усіх об‟єктів програми (у зворотному порядку), у тому числі повторює повідомлення про об‟єкт a11.

14.7 Успадкування

Успадкування (inheritance) – це механізм, за допомогою якого один об‟єкт може набувати властивості іншого. Точніше, об‟єкт може успадковувати основні властивості іншого об‟єкта та набувати нових рис, які характерні лише для нього. Успадкування є дуже важливим, оскільки воно дозволяє підтримувати принцип ієрархії класів (hierarchical classification). Наприклад, клас мобільних

516

Розділ 14

 

 

телефонів є підкласом класу “Телефон”, який, у свою чергу, входить до ще більшого класу “Електрозв‟язок”. Разом з тим, клас “Електрозв‟язок” є підкласом класу “Способи зв‟язку”, до складу якого, крім електрозв‟язку, входять супутниковий зв‟язок, радіозв‟язок, поштовий зв‟язок тощо (рис. 14.1). Застосування ієрархії класів дозволяє керувати великими потоками інформації. Прикладом подібної ієрархії є системи класифікації в ботаніці, зоології тощо.

 

 

 

 

Способи зв‟язку

 

Базовий клас

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Клас 1-го рівня

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Супутниковий

 

 

Поштовий

 

Радіозв‟язок

 

 

Електро-

 

 

 

 

 

 

 

зв‟язок

 

 

зв‟язок

 

 

зв‟язок

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Телеграф

 

 

Телефон

...

Клас 2-го рівня

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Мобільний

 

 

Стаціонарний

... Клас 3-го рівня

 

 

 

 

 

 

 

 

 

Рис. 14.1. Ієрархія класів “Способи зв‟язку”

В об‟єктно-орієнтованому програмуванні успадкування – це процес створювання нових класів, які називають похідними класами (нащадками) на базі вже існуючих батьківських (базових) класів. Похідний клас успадковує всі можливості батьківського (базового) класу, але може бути удосконаленим за рахунок змінювання існуючих методів і долучення нових власних полів та методів. Батьківський клас (чи клас вищого рівня) при цьому залишається незмінним. Похідний клас (клас нижчого рівня), у свою чергу, сам може слугувати за батьківський.

Найважливішою позитивною якістю успадкування в ООП є те, що воно дає можливість уникати повторювань програмного коду для кожного об‟єкта, адже спільний для множини подібних класів код може бути винесено до методів їхнього спільного батьківського класу. Це є доволі зручний спосіб, оскільки програміст може використовувати класи, створені будь-ким іншим, без модифікації коду, лише створюючи похідні класи.

Успадкування буває простим і множинним. Простим називається успадкування, за якого похідний клас має один батьківський клас. Множинне успадкування означає, що клас має кілька батьківських класів, і застосовується для того, щоб забезпечити похідний клас їхніми властивостями. При застосовуванні множинного успадкування треба ретельно стежити за тим, щоби похідний клас не успадкував поля чи методи з однаковими іменами, але різні за змістом.

Об’єктно-орієнтоване програмування

517

 

 

Для створювання похідного класу використовують ключове слово class, після якого записують ім‟я нового класу, двокрапку (:), ключ доступу класу (public, private, protected), а потім зазначають ім‟я батьківського класу:

сlass

<ім‟я_похідного_класу>:[<ключ_доступу>]<ім‟я_батьківського_класу> { <тіло_класу> };

Вище розглядались лише специфікатори доступу private (закритий) та public (відкритий), які застосовуються до полів класу. Однак члени базового класу, оголошені як private, у похідному класі є недоступні незалежно від ключа доступу. Звертання до них може відбуватися лише через методи базового класу. Для базових класів можливе використання ще одного специфікатора – protected (захищений), який для поодиноких класів, що не входять до ієрархії, означає те ж саме, що й private.

Ключ доступу public означає, що всі відкриті й захищені члени базового класу стають такими для похідного класу. Ключ доступу private означає, що всі відкриті й захищені члени базового класу стають закритими членами для похідного класу. Ключ доступу protected означає, що всі відкриті й захищені члени базового класу стають захищеними членами похідного класу.

Розглянемо успадкування класів на прикладі.

Приклад 14.5. Створити клас – “два дійсних числа”, які можуть відображати значення висоти та ширини геометричної фігури. На базі цього класу створити два похідні класи: “прямокутник”, який обчислює площу прямокутника, та “циліндр”, який обчислює площу бокової поверхні циліндра. Для класу “прямокутник” створити похідний клас “паралелепіпед”, який обчислює об‟єм паралелепіпеда з використання параметра – значення висоти. Ієрархію цих класів наведено на рис 14.2.

Клас – два дійсних числа

Клас – прямокутник

 

Клас – циліндр

 

 

 

Клас – паралелепіпед

Рис. 14.2. Ієрархія класів для прикладу 14.5

Код програми:

#include <vcl.h> #pragma hdrstop #include "Unit1.h"

//-------------------------------------------------------------

#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1;

//-------------------------------------------------------------

518

Розділ 14

 

 

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)

{

}

//-------------------------------------------------------------

class areal_r_c // Оголошення батьківського класу «два дійсних числа» { protected: // Забезпечення доступу до даних похідного класу

float heigth, width ;

}; // Оголошення похідного класу “прямокутник”

class rectangle : public areal_r_c

{ public:

rectangle(float h, float w); float arear();

}; // Реалізація методів похідного класу “прямокутник”

rectangle::rectangle(float h, float w)

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

{ heigth=h;

width=w; }

 

float rectangle::arear()

// Обчислення площі

{ return heigth*width; }

 

// Оголошення похідного класу “циліндр”

 

class cylinder : public areal_r_c

 

{ public:

 

 

cylinder (float h, float w);

 

float areac();

 

};

 

 

// Реалізація методів похідного класу “циліндр”

 

cylinder::cylinder(float h, float w)

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

{ heigth=h;

width=w; }

 

float cylinder::areac() // Обчислення бокової поверхні циліндра

{ return 3.14*width*heigth; }

//Оголошення класу “паралелепіпед”, похідного від класу “прямокутник” class paral : public rectangle

{ public: float hv;

paral(float h, float w, float hh); float areap();

};

//Реалізація методів похідного класу “паралелепіпед”

paral :: paral(float h, float w, float hh) : rectangle(h, w)

{ hv=hh; }

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

float paral::areap()

// Обчислення об‟єму паралелепіпеда з використанням

{ return rectangle::arear()*hv; } // методу arear батьківського класу

//----- Відгук на кнопку “Обчислити”--------------------

void __fastcall TForm1::Button1Click(TObject *Sender) { // Створення об‟єктів класів

rectangle b(StrToFloat(Edit1->Text),StrToFloat(Edit2->Text)); cylinder c(StrToFloat(Edit3->Text),StrToFloat(Edit4->Text));

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]