1. Бублик Володимир Васильович Програмування - 2 Лекція 1. Об'єктне програмування. Принцип інкапсуляції Лекції для студентів 2 курсу
2. Інкапсуляція Під інкапсуляцією розумітимемо спосіб збирання певних елементів в одне ціле з метою утворення нової сутності (або абстракції нового рівня) Команди інкапсульовані в функцію Поля інкапсульовані в структуру struct Point { double _x; double _y; }
3. Дані і функції в структурах ( як С моделює С++) Чи можна інкапсулювати функцію в структуру? struct QuasiPoint { double _x; double _y; // інкапсуляція указника на функцію double ( *f )(QuasiPoint, QuasiPoint); }; Як викликати f?
4. Виклик інкапсульованої функції double distance (QuasiPoint, QuasiPoint); double phi (QuasiPoint, QuasiPoint); QuasiPoint u={0, 1 }, v={1,1}; u.f = distance; cout<<u.f(u,v)<<endl; v.f = phi; //це добре чи зле? cout<< v .f(u,v)<<endl; Як засобами С зробити так, щоб для всіх екземплярів QuasiPoint указник показував завжди одну й ту ж функцію?
5. Статичний указник на функцію struct QuasiPoint { double _x; double _y; // інкапсуляція указника на функцію static double ( *f )(QuasiPoint, QuasiPoint); }; // Один указник для всіх об ’ єктів double (*QuasiPoint::f)(QuasiPoint,QuasiPoint)= distance; cout<< QuasiPoint:: f(u,v)<<endl;
6. Створення і видалення екземпляру структури struct Pre WrappedVector { static const int _n; double * _v; }; // Функція створення вектора a._v void construct ( Pre WrappedVector& a); // Функція видалення вектора a._v void destroy ( Pre WrappedVector& a);
7. Створення і видалення екземпляру структури // Типовий сценарій обробки Pre WrappedVector v; // Хто гарантує створення вектора // до першого вживання? construct(v); ………………………… destroy(v); // Хто гарантує виклик функції видалення // після закінчення обробки вектора?
8. Конструктор і деструктор struct WrappedVector { static const int _n; double * _v; // Це конструктор, він створює об'єкт // при його визначенні WrappedVector(); // Це деструктор, він автоматично видаляє об'єкт ~WrappedVector(); };
9. Реалізація конструктора WrappedVector::WrappedVector() { cout<<"Constructor WrappedVector"<<endl; // 1. Виділити пам'ять _ v = new double [_n]; // 2. Можливо обробити аварійну ситуацію // 3. Ініціалізувати масив for ( int i=0; i<_n; i++) _v[i] = 0; return ; }
11. Автоматичний виклик конструктора і деструктора int main () { // Визначення об'єктів приводить // до виклику конструкторів. // Ось він: WrappedVector w1, w2; …………………………………………… // Життя об'єктів завжди закінчується // автоматичним викликом їх деструкторів // ост тут: return 0; }
12. new : конструктор ; delete : деструктор int main () { WrappedVector * pw; // Створення об'єкту: // неявний виклик конструктора pw = new WrappedVector ; ………………………………………………… // Видалення об'єкту: // неявний виклик деструктора delete pw; return 0; }
13. Конструктор і деструктор за замовчуванням Чи має структура Pre WrappedVector конструктора і деструктора, якщо вони не визначені явно ? struct Pre WrappedVector { static const int _n; double * _v; }
14. Конструктор і деструктор за замовчуванням Так! Компілятор генерує порожні конструктор і деструктор для кожної структури, яка не має власних // Конструктор за замовчуванням Pre WrappedVector:: Pre WrappedVector() { }; // Деструктор за замовчуванням Pre WrappedVector:: ~Pre WrappedVector() { }; // Краще б їх не було, але так досягається // сумісність С і С++
15. Поля(атрибути) і функції(методи) struct Point { // Атрибути double _x, _y; // Конструктор Point ( double x=0, double y=0): _x (x), _y (y) { }; // Деструктор ~Point(){}; // Функції доступу до атрибутів – методи double & x() { return _x ;} double & y() { return _y ;} };
16. Виклик конструктора з параметрами // Замість Point a = Point(1,2); // пишемо скорочено Point a1(1,2); Point b = Point(1); Point b1(1); Point c = Point(); Point c1;
17. Виклик методів Виклик методів відрізняється від виклику звичайних функцій // Застосувати до екземпляру а структури Point // функцію х() a.x() = 10; cout<< a.x() <<endl;
18. Варіант: утиліта struct Point { // Атрибути double _x, _y; // Конструктор Point ( double x=0, double y=0): _x (x), _y (y) { }; // Деструктор ~Point(){}; } // Утиліти доступу до атрибутів – методи double & x( Point & a ) { return a . _x;} double & y( Point & a ) { return a . _y;}
19. Виклик утиліти Виклик методів відрізняється від виклику звичайних функцій // Передати до функції x() параметр a x(a) = 10; cout<< x(a) <<endl;
20. Прямий доступ Замість функкції x(a) або методу a.x() можна було б напряму звертатися до члена структури _x a. _ x = 10; cout<< a. _ x <<endl;
21. Для чого потрібні методи доступу? struct Point { private: // закрили прямий доступ до атрибутів double _x; double _y; public: // відкрили доступ до методів Point ( double x=0, double y=0): _x(x),_y(y) { }; ~Point(){}; double & x() { return _x;} double & y() { return _y;} };
22. Права доступу Як і раніше кожен, хто бачить об'єкт може скористатися його відкритим методом // Застосувати до екземпляру а структури Point // відкритий метод х() a.x() = 10; cout<< a.x() <<endl;
23. Права доступу Сам метод, завдяки своїй належності до структури сам бачить її закриту частину // Як і раніше, ім'я _х в тексті функції double & x() { return _x ;} // позначає поле _х того екземпляру, // до якого застосовано функцію
24. Права доступу Але для сторонніх атрибути стали невидимими int main () { Point a; a. _ x = 10; cout<< a. _ x <<endl; return 0; } double & x( Point & a ) { return a. _x ;} double & y( Point & a ) { return a. _y ;}
25. Клас class Point { private: // закрита частина класу double _x; double _y; public: // відкрита частина класу Point ( double x=0, double y=0): _x(x),_y(y) { }; ~Point(){}; double & x() { return _x;} double & y() { return _y;} };
26. Об'єкт Структуру, яку поділено на відкриту і закриту частини називатимемо класом . Зазвичай структура відкрита. Екземпляри класів називатимемо об'єктами . Кожен об'єкт створюється в результаті виклику конструктора, а видаляється деструктором. Клас завжди має конструктори (можливо декілька) і деструктор. Ніколи не вживайте конструктор і деструктор за замовчуванням (подарунок системи програмування) тому, що За це ВВ поставить “ двійку ” Ви не зможете контролювати моменти створення і видалення об'єктів
27. Клас vs. структура Правила доступу ― це поділ класу на відкриту ( public ) і закриту ( private ) частини . Закрита частина доступна лише з середини класу, відкрита ― звідусіль. Формально клас відрізняється від структури лише правилом замовчування прав доступу: Все, що явно не відкрите в класі, вважається закритим Все, що явно не закрите в структурі, вважається відкритим Структури звичайно вживають як сукупність даних, класи ― як сукупність даних (атрибутів) і функцій-членів класу (методів)
28. Повторення. Два способи запису ініціалізації double x = 1.0; double y = x; double u = 2.0; // але можна й так double v(u); // це те ж саме, що // double v = u;
30. Ініціалізація атрибутів в конструкторі class Complex { private : double _re; double _im; public : Complex ( double re, double im): // ініціалізація атрибутів ( погана! ) { _re = re ; _im = im ; };
31. Приклад 1. Person.h class Person { private : const int _len; char * _name; public : // реалізація винесена в срр-файл Person( int , char []); ~Person(); };
32. Приклад 1. Person.cpp (конструктор) Person::Person ( int len, char name []): _len(len) , _name ( new char [_len+1] ) ; { for ( int i=0; i<_len; i++) _name[i] = name[i]; _name[_len]='\0'; cout<<"A person "<<_name<<" was created"<<endl; return ; }
33. Приклад 1. Person.cpp (деструктор) Person::~Person() { cout<<"A person "<<_name<<" was deleted"<<endl; delete [] _name; // _name = 0; зайве, оскільки сам об'єкт, // а значить і його атрибут _name , // припиняють своє існування return ; }
34. Приклад 2. WrappedVector.h class WrappedVector { private : static const int _n; double * _v; public : WrappedVector(); ~WrappedVector(); };
35. Приклад 2. WrappedVector.cpp const int WrappedVector::_n = 100; WrappedVector::WrappedVector() : _v ( new double [_n]; ) { cout<<"Constructor WrappedVector"<<endl; for ( int i=0; i<_n; i++) _v[i] = 0; return ; }
37. Селектори і модифікатори Як добратися до атрибутів, якщо вони закриті? ― За допомогою методів доступу: селекторів і модифікаторів Два в одному double & x() { return _x ;} 2а. Селектор double getX() { return _x ; } ; 2 b. Модифікатор void setX ( double x) { _x = x;}
38. Приклад 2. WrappedVector. Селектор-модифікатор class WrappedVector { private : static const int _ n; double * _ v; public : class BadIndex { }; double & getSet ( int i); WrappedVector(); ~WrappedVector(); };
39. Приклад 2. WrappedVector. Селектор-модифікатор double & WrappedVector :: getSet ( int i) { if ((i<0) !! (i>=_len)) throw BadIndex; return _v[i]; } WrappedVector u; u.getSet(0) = 500; cout<<u.getSet(0)<<endl; // А хотілося б u[i] . ― Далі буде
40. Приклад 2. WrappedVector. Селектор і модифікатор double WrappedVector :: get (int i) { if ((i<0) !! (i>=_len)) throw BadIndex; return _v[i]; } void WrappedVector :: set ( int i, double x) { if ((i<0) !! (i>=_len)) throw BadIndex; _v[i] = x; return ; }
41. Чому віддавати перевагу Окремий модифікатор дозволяє контролювати кожну спробу зміни значення атрибуту, а селектор ― кожне використання його значення. Модифікатор-селектор не відрізняє зміну значення від читання, контролює спробу доступу. Кожна мова програмування пропонує оператор індексування [ ] ― по суті селектор-модифікатор.
42. Що вживати: клас чи структуру? Слідкуємо за створенням і видаленням об'єктів, регламентуємо доступ до його частин ― вживаємо клас. Обов'язкові конструктор(и) і деструктор, модифікатори і селектори для кожного призначеного для використання зовні атрибуту. Правило доступу: Атрибути, як правило , закриті; методи можуть бути відкриті. В інших випадках можна обходитися структурами
43. Об'єкт – екземпляр класу Об'єкт характеризується ідентичністю, станом і поведінкою. Ідентичність ― це властивість, що відрізняє об'єкт від усіх інших об'єктів. Об'єкт набуває ідентичності при створенні його конструктором і втрачає її при видаленні його деструктором. Стан визначається набором значень атрибутів об'єкту. Поведінка визначається набором методів.
44. Висновок Вивчили Як створити об'єкт в заданому початковому стані Як змінити стан об'єкту Як визначити стан об'єкту Як видалити об'єкт Наступна задача: наділити об'єкти поведінкою