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

Зубенко, Омельчук - Програмування. Поглиблений курс

.pdf
Скачиваний:
51
Добавлен:
07.03.2016
Размер:
4.72 Mб
Скачать

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

меження доступу до зміни значень елементів структури. Як наслідок це може викликати внесення неправильних дат (напр.: {35, 35, 35000}). Звичайно, можна замість int використовувати деякі його обмеження, але це не може адекватно розв'язати проблему різної кі- лькості днів у місяцях тощо. Крім того, нехай після реалізації певної кількості функцій із використанням цієї структури ми вирішили, що зручніше буде змінити спосіб збереження часу, а саме зберігати кіль- кість днів, починаючи від фіксованої дати. Для цього потрібно:

змінити структуру CppDate, видаливши старі атрибути й додавши довге ціле (можна взагалі не використовувати структуру);

змінити всі функції, що використовують CppDate, а також модифі- кувати всі оператори, які оперують компонентами структури CppDate.

Для великих програм (кілька тисяч рядків) здійснити такі зміни до- сить складно, знадобиться повторне налагодження.

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

Основним засобом організації даних у мові C++ є класи. Зовні цей тип даних схожий на тип структур, однак полями (членами) у класі можуть бути не лише дані, але й методи (функції):

<клас>::=class <ім'я-класу>[:<список-батьківських класів>] \ {<cписок-секцій>};

<батьківський-клас>::=(public <ім'я-класу>|private <ім'я-класу>| protected <ім'я-класу>)

<секція>::=(public: <список-атрибутів-і-методів>| protected: <список-атрибутів-і-методів>| private: <список-атрибутів-і-методів>) <арибут>::=<опис-змінної> <метод>>::=<прототип-функції>|<опис-функції>

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

441

ПРОГРАМУВАННЯ

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

Більшість класів краще оголошувати в заголовних файлах, які по- тім можуть включатися в численні програмні модулі для сумісного використання класів.

Якщо останню програму переписати, використовуючи класи, то утвориться клас, зображений UML-діаграмою:

CDate

day : int

month : int year : int

getCountDayInMonth()

comparison()

printDate()

setDate()

getDate()

getMonth() getYear()

Перепишемо програму мовою C++, використовуючи класи.

Приклад 3.84.

Лістинг.

class CppDate{ private:

int day; int month; int year;

//кількість днів у місяці m року у; якщо рік і місяць некоректні, то 0

int getCountDayInMonth(int m, int y);

public:

/*порівняння дат: 0 – рівні, 1 – перша більша, -1 – друга більша*/

int comparison(CppDate dt1, CppDate dt2); //друкування дати

void printDate();

//установлення дати

442

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

void setDate(int d, int m, int y); //повернення дня

int getDay(); //повернення місяця int getMonth(); //повернення року int getYear();

};

/*порівняння дат 0 – рівні, 1 – перша більша, -1 – друга більша*/ int CppDate::comparison(CppDate dt)

{

if(year>dt.year) return 1; if(year<dt.year) return -1; if(month>dt.month) return 1; if(month<dt.month) return -1; if(day>dt.day) return 1; if(day<dt.day) return -1; return 0;

}

//друкування дати

void CppDate::printDate()

{

char buffer[32];

sprintf(buffer, "Date: %02d.%02d.%04d\n", day, month, year); cout<<buffer;

}

//ініціалізує дату – за умови некоректних даних присвоює нульові елементи

void CppDate::setDate(int d, int m, int y)

{

if((d>=1)&&(d<=getCountDayInMonth(m, y)))

{

day=d;

month=m;

year=y;

}

else

{

day=0;

month=0;

year=0;

}

}

443

ПРОГРАМУВАННЯ

//кількість днів у місяці m року у; якщо рік і місяць некоректні, то 0

int CppDate::getCountDayInMonth(int m, int y)

{

if((y>=1900)&&(y<=3000))

{

switch (m)

{

case 1:

case 3: case 5: case 7: case 8: case 10: case 12:

return 31; case 4:

case 6: case 9: case 11:

return 30;

case 2: if(!(y%4)&&((y%100)))

return 29;

else

return 28;

default: return 0;

}

}

else

return 0;

}

int CppDate::getDay()

{

return day;

}

int CppDate::getMonth()

{

return month;

}

int CppDate::getYear()

{

444

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

return year;

}

Зауважимо: атрибути day, month, year приватні, – це гарантує, що жодним іншим чином у програмі, окрім методів, описаних у класі (тут setDate()), не можна отримати доступ до них. У такий спосіб гаран- тується перевірка правильності введення даних. Для зміни подання дати (напр., кількості днів від заданої дати) потрібно лише внести зміни в клас і відредагувати методи для роботи з новою структурою. Якщо при цьому зберегти інтерфейс методів, то зовнішнє застосуван- ня класу не зміниться

Приклад 3.85. Використання вбудованих (inline) методів.

У заданому вище описі класу в його тілі зазначено лише заголовки методів (функцій), а можна описати в тілі класу весь метод (він нази- вається вбудованим inline). Наприклад, у розглянутому вище при- кладі доцільно описати клас таким чином:

Лістинг.

class CppDate{ private:

int day; int month; int year;

//кількість днів у місяці m року у; якщо рік і місяць не коректні, то 0

int getCountDayInMonth(int m, int y);

public:

/*порівняння дат: 0 – рівні, 1 – перша більша, -1 – друга більша*/

int comparison(CppDate dt2);

//друкування дати void printDate();

//установлення дати

void setDate(int d, int m, int y);

//повернення дня (inline-метод) int getDay()

{

return day;

}

//повернення місяця (inline-метод)

445

ПРОГРАМУВАННЯ

int getMonth()

{

return month;

}

//повернення року (inline-метод) int getYear()

{

return year;

}

};

Метод класу можна також описати як вбудований поза описом класу:

class CppDate{ private:

int day; int month; int year;

/*кількість днів у місяці m року у, якщо рік і місяць некоректні, то 0*/

int getCountDayInMonth(int m, int y);

public:

/*порівняння дат: 0 – рівні, 1 – перша більша, -1 – друга більша*/

int comparison(CppDate dt2);

//друкування дати void printDate();

//установлення дати

void setDate(int d, int m, int y);

//повернення дня (inline-метод) int getDay();

//повернення місяця (inline-метод) int getMonth();

//повернення року (inline-метод) int getYear();

};

//повернення дня (inline-метод) inline int CppDate::getDay();

{

return day;

}

//повернення місяця (inline-метод)

446

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

inline int CppDate::getMonth()

{

return month;

}

//повернення року (inline-метод) inline int CppDate::getYear();

{

return year;

}

3.11.2. ІНІЦІАЛІЗАЦІЯ, ПРИСВОЮВАННЯ ТА ЗНИЩЕННЯ КЛАСУ

Використання для ініціалізації об'єкта класу функцій, подібних setDate(), може призвести до помилок, оскільки програміст після створення об'єкта може забути викликати цю функцію або викликати її кілька разів. У C++ є можливість описати функцію, явно призначену для ініціалізації об'єктів. Така функція називається конструктором і має таке саме ім'я, як клас. Для класу можна описати кілька констру- кторів, тобто перевантажити конструктор.

Аналогічно можна описати деструктор метод, що викликається при знищенні об'єкта класу.

Приклад 3.86. Конструктори й деструктори:

Лістинг.

class CTree{ private:

CTree *m-pLeft; CTree *m-pRight; int m-iEl;

public: //конструктор 1

CTree(int el); //конструктор 2 CTree(); //конструктор 3

CTree(int el, CTree *left, CTree *right); //деструктор

~CTree();

}; //конструктор 1

447

ПРОГРАМУВАННЯ

CTree::CTree(int el)

{

m-iEl=el; m-pLeft=NULL; m-pRight=NULL;

}

//конструктор 2 CTree::CTree()

{

m-iEl=0; m-pLeft=NULL; m-pRight=NULL;

}

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

CTree::CTree(int el, CTree *left, CTree *right)

{

m-iEl=el; m-pLeft=left; m-pRight=right;

}

//деструктор

CTree::~CTree()

{

delete m-pLeft; delete m-pRight;

}

За умовчанням кожен клас має конструктор без параметрів і де- структор. Конструктор за умовчанням викликає конструктори всіх атрибутів, а деструктор їхні деструктори.

3.11.3. СПАДКУВАННЯ

Розглянемо другу властивість ООП, що реалізується в C++ – спад-

кування.

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

448

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

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

За умовчанням конструктор нащадка без параметрів викликає конструктор базового класу, а потім виконується сам. Інші конструк- тори (крім конструктора без параметрів) доводиться визначати кож- ного разу заново або явно описувати виклик конструктора базового класу. Деструктор нащадка навпаки, після виконання свого тіла викликає деструктор базового класу.

Нащадок можна використовувати всюди, де використовується базо- вий клас. Наприклад, якщо метод як параметр потребує об'єкт базового класу, то можна передати йому об'єкт класу-нащадка, але не навпаки.

У мові C++ спадкування буває публічним (public), захищеним (protected) і приватним (private). Специфікатори доступу членів ба- зового класу змінюються в нащадках таким чином:

при public-спадкуванні члени базового класу зберігають свій статус;

при protected-спадкуванні публічні члени базового класу стають захищеними членами нащадка;

при private-спадкуванні всі члени базового класу в нащадку стають private.

Приклад 3.87. Типи спадкування:

class CA {

...

};

class CB:public CA {

...

};

class CC:protected CA{

...

};

class CppD:private CA{

...

};

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

449

ПРОГРАМУВАННЯ

явно перетворений на покажчик на базовий клас. Детальніше про це буде сказано при вивченні перетворення типів у мові C++.

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

методи. Тому зручно скористатися такими структурами даних:

 

 

 

 

CFigure

 

 

 

клас фігур

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m_sName : char*

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CFigure()

 

 

 

 

 

клас

 

 

~CFigure()

 

 

 

клас кіл

 

 

getArea()

 

 

 

трикутників

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

спадкування

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CCircle

 

 

CTriangle

 

 

 

 

 

 

 

 

 

 

 

 

m_fR : float

 

 

 

 

 

 

 

 

 

 

CTriangle()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CCircle()

 

 

~CTriangle()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

~CCircle()

 

1

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

3

 

 

 

 

 

 

 

CCoord

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m_iX : int

 

клас

 

 

 

 

 

 

 

 

 

 

m_iY : int

 

 

 

 

 

 

 

 

 

координат

 

 

 

 

CCoord()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

~CCoord()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Як видно з діаграми, у даному випадку кілька класів (CTriangle, CCircle) спадкуються від одного базового (CFigure).

Опишемо класи для роботи із цими фігурами в мові C++:

Лістинг.

//клас координат class CCoord { public:

int m-iX; int m-iY; //конструктор

450

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