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

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

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

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

CCoord(int x, int y) { m-iX=x;

m-iY=y;

}

};

//клас фігур class CFigure{ protected:

char *m-sName; public:

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

CFigure(const char *s) { m-sName=strdup(s);

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

~CFigure() {

delete m-sName;

}

//знаходження площі float getArea();

}; //клас трикутників

class CTriangle:public CFigure { private:

CCoord *m-pA; CCoord *m-pB; CCoord *m-pC;

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

CTriangle(CCoord *a, CCoord *b, CCoord *c); //деструктор

~CTriangle(); //знаходження площі

float getArea();//площа

}; //клас кіл

class CCircle:public CFigure { private:

CCoord *m-pO; float m-fR;

public:

CCircle(CCoord *o, float r); ~CCircle();

//знаходження площі

float getArea();//площа

};

451

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

CTriangle::CTriangle(CCoord *a, CCoord *b, CCoord *c)

: CFigure("Triangle")//виклик конструктора базового класу

{

m-pA=new CCoord(a->m-iX, a->m-iY);

m-pB=new CCoord(b->m-iX, b->m-iY);

m-pC=new CCoord(c->m-iX, c->m-iY);

}

CTriangle::~CTriangle()

{

delete m-pA; delete m-pB; delete m-pC;

}

float CTriangle::getArea()//площа

{

floata=(m-pA->m-iX*(m-pB->m-iY – m-pC->m-iY)); float b=(m-pB->m-iX*(m-pC->m-iY – m-pA->m-iY)); float c=(m-pC->m-iX*(m-pA->m-iY – m-pB->m-iY)); //модуль

float d=a+b+c; if(d>0)

return (d/2);

else

return ((-1)*d/2);

}

CCircle::CCircle(CCoord *o, float r): CFigure("Square") //виклик конструктора базового класу

{

m-pO=new CCoord(o->m-iX, o->m-iY); m-fR=r;

}

CCircle::~CCircle()

{

delete m-pO;

}

float CCircle::getArea()

{

return m-fR*m-fR*3.1415;

}

Клас-нащадок, у свою чергу, сам може бути базовим:

452

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

 

 

CFigure

 

 

клас фігур

 

 

 

 

 

 

 

 

 

 

 

 

 

m_sName : char*

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CFigure()

 

 

 

 

 

 

 

~CFigure()

 

 

 

 

 

 

 

 

 

 

CCoord

 

 

 

getArea()

 

 

 

 

 

 

 

 

 

 

 

спадкування

 

 

 

 

m_iX : int

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m_iY : int

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CQuadrangle

 

 

 

1

CCoord()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

4

 

 

~CCoord()

 

 

 

CQuadrangle()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

~CQuadrangle()

 

 

 

 

 

 

клас

 

 

 

 

 

клас

 

клас

 

 

 

 

 

 

 

 

 

 

 

 

координат

 

 

 

 

 

чотирикутників

ромбів

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CRhombus

 

CSquare

клас

 

 

 

квадратів

CRhombus()

 

CSquare()

 

 

~CRhombus()

 

~CSquare()

 

 

 

 

 

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

Приклад 3.89. Множинне спадкування:

CTelephone

... телефон

...()

CCommunicator

...

...()

CComputer

...

...()

комп'ютер

комунікатор (гібрид комп'ютера та мобільного телефону)

453

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

У мові C++ це буде виглядати так:

class CTelephone {

};

class CComputer {

};

class CCommunicator:public CTelephone, public CComputer {

};

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

class CTelephone {

public:

void connection();

};

class CComputer {

public:

void connection();

};

class CCommunicator:public CTelephone, public CComputer {

//void connection(); не визначено!!!

};

void f(CCommunicator *p)

{

p->connection();//ПОМИЛКА! НЕОДНОЗНАЧНІСТЬ!

}

У C++ такі неоднозначності зазвичай усуваються введенням у клас- нащадок додаткової функції:

class CCommunicator:public CTelephone, public CComputer {

454

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

public:

void connection()

{

CTelephone::connection();

CComputer::connection();

}

};

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

3.11.4. ПОЛІМОРФІЗМ

Як зазначалося вище, поліморфізм забезпечується тим, що в класі- нащадку перевизначають методи батьківського класу. Це забезпечує збереження незмінним інтерфейсу батьківського класу й дозволяє здійснювати зв'язування імені методу в коді з різними класами (з об'єкта якого класу здійснюється виклик, з того класу й береться метод із заданим іменем). Такий механізм називається динамічним

(пізнім) зв'язуванням на відміну від статичного (раннього) зв'язу-

вання, що здійснюється на етапі компіляції.

Цей механізм уже було використано вище при вивченні спадку- вання (приклад про знаходження площ фігур, класи CFigure,

CTriangle, CСircle, метод float getArea(); //площа). Проте в тому випадку можливі були лише заздалегідь визначені виклики:

CCoord *a=new CCoord(1, 1); CCircle *sq=new CCircle(a, 10); cout<<"\nArea:"<<sq->getArea();

Однак поліморфні виклики спричинили б помилку. Приклад 3.90. Помилкові поліморфні виклики:

//ранній поліморфізм void f(CFigure *p)

{

455

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

//викличе метод базового класу cout<<"\nArea:"<<p->getArea();

}

або

CCoord *c1=new CCoord(10, 10);

CCoord *c2=new CCoord(100, 100);

CCoord *c3=new CCoord(25, 25);

//пізній поліморфізм

CFigure *p=new CTriangle(c1, c2, c3); //викличе метод базового класу

cout<<"\nArea:"<<p->getArea();

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

Приклад 3.91. Правильні поліморфні виклики:

class CFigure{ protected:

char *m-sName; public:

CFigure(const char *s) { m-sName=strdup(s);

}; ~CFigure() {

delete m-sName;

}

double getPerimeter();

/*const=0; – означає, що метод не реалізується в цьому класі; у такому разі метод називається чистою віртуальною функцією*/

virtual float getArea() const=0;

};

class CTriangle:public CFigure { private:

CCoord *m-pA; CCoord *m-pB; CCoord *m-pC;

public:

CTriangle(CCoord *a, CCoord *b, CCoord *c); ~CTriangle();

virtual float getArea() const; //площа

};

456

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

class CCircle:public CFigure { private:

CCoord *m-pO; float m-fR;

public:

CCircle(CCoord *o, float r); ~CCircle();

virtual float getArea() const; //площа

};

virtual float CCircle::getArea() const //площа

{

//без змін

}

virtual float CTriangle::getArea() const //площа

{

//без змін

}

//усе інше без змін

У даному випадку яка саме функція буде застосована визначається на етапі компіляції

Абстрактним називається клас, який містить хоча б один суто ві- ртуальний метод. Об'єкти таких класів створювати заборонено. Абст- рактні класи використовуються як інтерфейси.

*Література для CР: мова С++ – [57, 64, 70, 73, 96, 98, 102, 124].

Контрольні запитання та вправи

1.Як інкапсуляція подана в C++?

2.Що таке клас у C++?

3.Що таке атрибути й методи класу?

4.Що таке конструктор і деструктор класу та як їх описати в мові C++?

5.Як спадкування подано в C++?

6.Що таке публічне, захищене й приватне спадкування?

7.Що таке клас-нащадок і базовий клас?

8.Що таке множинне спадкування?

9.Які проблеми можуть виникнути при застосуванні множин- ного спадкування та як їх уникнути?

10.Як поліморфізм поданий у C++?

11.Що таке раннє й пізнє зв'язування?

12.Що робить метод віртуальним?

13.Що таке абстрактний клас?

457

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

14. Переписати програму з прикл. 3.84 для класу, де дата зо- бражується кількістю днів від заданої дати (напр.,

1.01.1900).

15.Подайте задану діаграму класів (прикл. 3.85) у мові C++ і реалізуйте відповідні методи.

16.Створити клас «Трикутник» із полями-сторонами. Визначи- ти методи зміни сторін, обчислення кутів, обчислення пери- метра. Створити клас-нащадок «Рівносторонній трикутник», який має поле площі. Визначити метод обчислення площі.

17.Написати функції для основних арифметичних операцій над раціональними числами й відношеннями на них (див. вправу 21, підрозд. 3.7). Раціональні числа подати у вигляді класу з атрибутами цілих типів, що задають чисельник і зна- менник.

18.Створити базовий клас «Пара цілих чисел» з операціями пе- ревірки на рівність і множення на число. Реалізувати опе-

рацію додавання пар за формулою (a,b)+(c,d ) = (a +b.c +d ).

Визначити клас-нащадок «Гроші» з полями «гривні й копій- ки». Перевизначити операцію додавання й визначити мето- ди віднімання й ділення грошових сум.

19.Написати програму для роботи з геометричними фігурами (трикутник, круг, прямокутник, квадрат, ромб). У програмі створити абстрактний базовий клас «Фігура» з віртуальними методами обчислення площі й периметра та його нащадків – «Трикутник», «Круг», «Прямокутник», «Квадрат», «Ромб».

20.Створити абстрактний клас «Трикутник» із віртуальними методами обчислення площі й периметра. Поля даних пови- нні мати дві сторони й кут між ними. Визначити класи- нащадки «Прямокутний трикутник» і «Рівнобедрений трику- тник» зі своїми функціями обчислення площі й периметра.

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

каталог книг у бібліотеці;

список студентів у групі;

список товарів у магазині ;

список клієнтів банку;

телефонний довідник.

22.Реалізувати калькулятор числових константних арифметичних виразів. Додати в нього можливість вводити власні функції, запам'ятовувати константи, використовуючи засоби мови С++ (перевантаження операторів, бібліотеку STL, простори імен).

458

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

23.Реалізувати й увести в калькулятор додаткові алгебри (комплексні, раціональні числа, вектори, матриці) як окремі класи.

24.Реалізувати введення й виведення елементів комплексних чисел, перевантаживши оператори <<&>> в oistream.

25.Реалізувати просту текстову віконну систему, створивши відповідну ієрархію класів.

3.12.Інші засоби C++

¾Шаблони

¾Перетворення типів у мові C++

¾Друзі

¾Перевантаження операцій

¾Виключення. Блок try-catch-throw

Ключові слова: шаблон функції, вбудований, зовнішній і перевантажений шаблони, конкретизація (інстанціювання), шаблон класу, стандартна бібліотека шаблонів STL, примусове перетворення типів зі специфікаторами: static-cast, dynamic-cast, const-cast, reinterpret-cast, знижувальне зведення, друзі (friend),

функції- й методи-друзі, перевантаження операцій, виключення, виняткова ситуа- ція, обробка виключення, конструкції try, catch та throw.

3.12.1. ШАБЛОНИ

У мові C++ можна створювати шаблони (узагальнені функції), ви- користовуючи ключове слово template.

Шаблони функцій описують їхні загальні властивості, зазначають специфікації для функцій і класів, але не деталі реалізації. Шаблони особливо корисні в бібліотеках класів. Зазвичай вони розміщуються в заголовних файлах.

У шаблонів можуть бути параметри-типи й параметри-константи, що є фіксованими константними виразами. Будь-який із типів int, double, char *, vector<int>, list<double> є припустимим аргументом шаблона:

<оголошення-шаблона>::=template <<список-параметрів>> <функція-з-параметрами-зі-списку-параметрів>

459

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

Тут зовнішні кутові дужки (<, >) є частиною визначення шаблона. Якщо шаблон функції має кілька параметрів-типів, то кожному з

них повинно передувати ключове слово class чи typename.

Подібно до звичайних функцій, шаблон функції може бути оголо- шений як inline чи extern, а також перевантажений.

Процес підстановки типів і значень замість параметрів називаєть-

ся конкретизацією (інстанціюванням) шаблона.

Визначимо функцію max для довільних типів. Приклад 3.92. Визначення функції max через шаблони:

template <class T> T max(T a, T b)

{

if(a>b) return a; else return b;

}

template <class T> inline

T min(T a, T b)

{

if(a<b) return a; else return b;

}

Викликати ці функції можна таким чином:

max(3, 10);/*конкретизація екземпляра функції max, де T int*/ max(3.5, 5.4);/*конкретизація екземпляра функції max, де T double*/ max('a', 'b');/*конкретизація екземпляра функції max, де T char*/ max(string("sss"), string("rrr"));/*конкретизація екземпляра

функції max, де T string*/

min(3, 10);/*конкретизація екземпляра функції min, де T int*/ min(3.5, 5.4);/*конкретизація екземпляра функції min, де T double*/ min('a', 'b');/*конкретизація екземпляра функції min, де T char*/ min(string("sss"), string("rrr"));/*конкретизація екземпляра

функції min, де T string*/

У шаблонах можна використовувати більше одного типу. Приклад 3.93. Шаблон функції з кількома параметрами-класами:

template <class T1, class T2> T1 fun(T1 a, T2 b)

460