05 Operations And Utilities

574 views

Published on

Published in: Technology, Business
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
574
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

05 Operations And Utilities

  1. 1. Бублик Володимир Васильович Програмування - 2 Лекція 3 . Об'єктне програмування. Програмовані операції Лекції для студентів 2 курсу
  2. 2. Операторні вирази <ul><li>Як правильно прочитати вираз a+b? </li></ul><ul><li>Залежно від того, як визначена операція додавання для типів даних a i b </li></ul>
  3. 3. Утиліта класу <ul><li>const T operator +( const T&, const T&); </li></ul><ul><li>Тоді вираз </li></ul><ul><li>a+b; ( INFIX ) </li></ul><ul><li>читається як </li></ul><ul><li>operator +(a, b); ( PREFIX ) </li></ul><ul><li>Запис ( PREFIX ) повністю коректний, хоча всі віддають перевагу ( INFIX ) </li></ul>
  4. 4. Метод класу <ul><li>const T T:: operator +( const T&) const ; </li></ul><ul><li>Тепер вираз </li></ul><ul><li>a+b; ( INFIX ) </li></ul><ul><li>читається вже як </li></ul><ul><li>a. operator +(b); ( REQUEST ) </li></ul><ul><li>Запис ( REQUEST ) повністю коректний, хоча всі віддають перевагу ( INFIX ) </li></ul>
  5. 5. Метод vs утиліта <ul><li>Методи </li></ul><ul><li>Конструктор (звичайний і копіювальний), </li></ul><ul><li>Деструктор, </li></ul><ul><li>Присвоєння </li></ul><ul><li>Причина </li></ul><ul><li>Якщо в класі не визначені власні конструктори, деструктор або присвоєння, автоматично клас доповнюється відповідними методами за замовчуванням </li></ul>
  6. 6. Метод vs утиліта <ul><li>Методи </li></ul><ul><li>Мають повний доступ до закритої частини класу </li></ul><ul><li>Особливість типу першого аргументу ( this ) </li></ul><ul><li>Утиліти </li></ul><ul><li>Не мають повного доступу до закритої частини класу, якщо тільки їм не надано виняткових прав </li></ul><ul><li>Всі аргументи рівноправні </li></ul>
  7. 7. Утиліта додавання <ul><li>const Point operator + ( const Point & u, const Point & v) </li></ul><ul><li>{ </li></ul><ul><li>// доступ до координат точки за селекторами </li></ul><ul><li>return Point ( u.x()+v.x(), u.y()+v.y() ); </li></ul><ul><li>} </li></ul>
  8. 8. Груба помилка <ul><li>class Point </li></ul><ul><li>{ </li></ul><ul><li>// немає підстав надавати виняткові права </li></ul><ul><li>friend Point operator +( const Point &, const Point & ) ; </li></ul><ul><li>double _x; </li></ul><ul><li>double _y; </li></ul><ul><li>public : </li></ul><ul><li>Point ( double x=0, double y=0 ); </li></ul><ul><li>Point ( const Point &); </li></ul><ul><li>~Point() ; </li></ul><ul><li>}; </li></ul>
  9. 9. Невиправдане порушення прав доступу <ul><li>Прямий доступ до атрибутів нічого корисного не дає </li></ul><ul><li>Point operator + ( const Point & u, const Point & v) </li></ul><ul><li>{ </li></ul><ul><li>return Point ( u. _ x+v. _ x, u. _ y+v. _ y ); </li></ul><ul><li>} </li></ul>
  10. 10. Утиліта vs. метод <ul><li>У власному класі можна одну і ту ж операцію за бажанням визначити як метод або утиліту, але не одне та інше одночасно </li></ul><ul><li>Додавати власні методи до чужого класу не дозволяється. Можна, правда, визначити власний варіант чужого класу, додавши до нього все, що завгодно, але про це пізніше. </li></ul>
  11. 11. Утиліти <ul><li>bool operator ==( const Point & u, const Point & v) </li></ul><ul><li>{ </li></ul><ul><li>return ( u.x () == v.x () ) && (u.y () == v.y () ); </li></ul><ul><li>} </li></ul><ul><li>const Point operator+ ( const Point & u, const Point & v) </li></ul><ul><li>{ </li></ul><ul><li>return Point ( u.x()+v.x(), u.y()+v.y() ); </li></ul><ul><li>} </li></ul><ul><li>Утиліта не знає this </li></ul>
  12. 12. Приклад. Операції, реалізовані методами <ul><li>class Point </li></ul><ul><li>{ </li></ul><ul><li>private: </li></ul><ul><li>double _x , _y; </li></ul><ul><li>public : </li></ul><ul><li>bool operator ==( const Point &) const; </li></ul><ul><li>const Point operator + ( const Point &) const; </li></ul><ul><li>}; </li></ul>
  13. 13. Реалізація методів <ul><li>bool Point :: operator ==( const Point & u) const </li></ul><ul><li>{ </li></ul><ul><li>return ( this-> x () == u.x () ) && ( this-> y () == u.y () ); </li></ul><ul><li>} </li></ul><ul><li>const Point Point :: operator + ( const Point & v) const </li></ul><ul><li>{ </li></ul><ul><li>return Point ( this-> x () +v.x () , this-> y () +v.y () ); </li></ul><ul><li>} </li></ul>
  14. 14. Реалізація методів (без явного this ) <ul><li>bool Point :: operator ==( const Point & u) const </li></ul><ul><li>{ </li></ul><ul><li>return ( x () == u.x () ) && ( y () == u.y () ); </li></ul><ul><li>} </li></ul><ul><li>const Point Point :: operator + ( const Point & v) const </li></ul><ul><li>{ </li></ul><ul><li>return Point ( x () +v.x () , y () +v.y () ); </li></ul><ul><li>} </li></ul>
  15. 15. Погана реалізація методів <ul><li>bool Point :: operator ==( const Point & u) const </li></ul><ul><li>{ </li></ul><ul><li>return ( _x == u._x ) && ( _y == u._y ); </li></ul><ul><li>} </li></ul><ul><li>const Point Point :: operator + ( const Point & v) const </li></ul><ul><li>{ </li></ul><ul><li>return Point ( _x+v._x, _y+v._y ); </li></ul><ul><li>} </li></ul><ul><li>// Сумлінний охоронник реєструє кожного: </li></ul><ul><li>// свого і чужого </li></ul>
  16. 16. Приклад. Операції, реалізовані утилітами <ul><li>class Point </li></ul><ul><li>{ </li></ul><ul><li>private: </li></ul><ul><li>double _x , _y; </li></ul><ul><li>public : </li></ul><ul><li>// bool operator==(const Point &) const; </li></ul><ul><li>// const Point operator+ (const Point &) const; </li></ul><ul><li>}; </li></ul><ul><li>const Point operator + ( const Point &, const Point &) ; </li></ul><ul><li>bool operator ==( const Point &, const Point &); </li></ul>
  17. 17. Довизначення (overloading) операцій <ul><li>Довизначенню підлягають операції, хоча б один аргумент яких належить програмованому типу: класу, структурі або переліку </li></ul><ul><li>Довизначення можливе як у формі члена класу (методу), так і позакласної функції (утиліти) </li></ul>
  18. 18. Довизначення (overloading) операцій <ul><li>Зауваження . Уникайте терміну перевизначення. Ми сказали б, що операція додавання перевизначена для точок площини, якби спочатку там була б якась операція додавання, яку ми потім замінили іншою. Таке буде далі, називатиметься overriding , а не overloading </li></ul><ul><li>Зараз же ми розповсюджуємо операцію, наприклад, додавання, визначену на числах, рядках, тощо, на новий клас. </li></ul><ul><li>Перевизначенням можна було б називати хіба що присвоєння, адресування або кому оскільки вони завжди передвизначені </li></ul>
  19. 19. Не підлягають довизначенню <ul><li>Операція . доступу до поля структури-члена класу; </li></ul><ul><li>Операція .* доступу до поля за указником поля; </li></ul><ul><li>Операція :: розв'язання області дії; </li></ul><ul><li>Операція ?: імплікації </li></ul>
  20. 20. Суміщені присвоєння <ul><li>// += , -=, *=, /= </li></ul><ul><li>// Член класу </li></ul><ul><li>Complex& Complex:: operator +=( const Complex& a) </li></ul><ul><li>{ </li></ul><ul><li>_re += a._re; </li></ul><ul><li>_im += a._im; </li></ul><ul><li>return * this ; </li></ul><ul><li>} </li></ul>
  21. 21. Суміщені присвоєння <ul><li>// += , -=, *=, /= </li></ul><ul><li>// Член класу (інша реалізація) </li></ul><ul><li>Complex& Complex:: operator +=( const Complex& a) </li></ul><ul><li>{ </li></ul><ul><li>re() += a.re () ; </li></ul><ul><li>im () += a.im () ; </li></ul><ul><li>return * this ; </li></ul><ul><li>} </li></ul>
  22. 22. Суміщені присвоєння <ul><li>// += , -=, *=, /= </li></ul><ul><li>// Утиліта </li></ul><ul><li>Complex& operator +=(Complex& a, const Complex& b) </li></ul><ul><li>{ </li></ul><ul><li>// Bad solution (why?) </li></ul><ul><li>// a = a+b; </li></ul><ul><li>a. r e() += b. r e(); </li></ul><ul><li>a. i m() += b. i m(); </li></ul><ul><li>return a; </li></ul><ul><li>} </li></ul>
  23. 23. Арифметичні операції <ul><li>унарний + (тотожній оператор); </li></ul><ul><li>унарний - (зміна знаку на протилежний); </li></ul><ul><li>бінарний + (додавання); </li></ul><ul><li>бінарний - (віднімання); </li></ul><ul><li>бінарний * (множення); </li></ul><ul><li>бінарний / (частка від ділення); </li></ul><ul><li>бінарний % (остача від ділення); </li></ul>
  24. 24. Приклад. Комплексні утиліти <ul><li>const Complex operator + </li></ul><ul><li> ( const Complex&, const Complex&); </li></ul><ul><li>const Complex operator - </li></ul><ul><li> ( const Complex&, const Complex&); </li></ul><ul><li>const Complex operator * </li></ul><ul><li> ( const Complex&, const Complex&); </li></ul><ul><li>const Complex operator / </li></ul><ul><li> ( const Complex&, const Complex&); </li></ul><ul><li>bool operator == ( const Complex&, const Complex&); </li></ul><ul><li>bool operator != ( const Complex& a, const Complex& b) </li></ul><ul><li>{ return !(a==b);} </li></ul>
  25. 25. Приклад. Комплексні методи <ul><li>const Complex Complex:: operator +( const Complex&) const ; </li></ul><ul><li>const Complex Complex:: operator -( const Complex&) const ; </li></ul><ul><li>const Complex Complex:: operator *( const Complex&) const ; </li></ul><ul><li>const Complex Complex:: operator /( const Complex&) const ; </li></ul><ul><li>bool Complex:: operator == ( const Complex&) const ; </li></ul><ul><li>bool Complex:: operator != ( const Complex& b) const </li></ul><ul><li>{ return !(a==b);} </li></ul>
  26. 26. Властивості арифметичних операцій <ul><li>Не порушуйте традиційних властивостей арифметичних операцій </li></ul><ul><li>// Скалярний добуток векторів </li></ul><ul><li>с onst Vector Vector:: operator *( const Vector &) const ; </li></ul><ul><li>// Асоціативність </li></ul><ul><li>Vector u, v, w; </li></ul><ul><li>// u*v*w? ― ERROR!!! </li></ul>
  27. 27. Властивості арифметичних операційй <ul><li>// Скалярний добуток векторів </li></ul><ul><li>с onst Vector Vector:: operator *( const Vector &) const ; </li></ul><ul><li>с onst Vector Vector:: operator *( const double ) const ; </li></ul><ul><li>// Асоціативність </li></ul><ul><li>Vector u, v, w; </li></ul><ul><li>// ОК </li></ul><ul><li>u* ( v*w ); </li></ul>
  28. 28. Властивості арифметичних операційй <ul><li>// Скалярний добуток векторів </li></ul><ul><li>с onst Vector Vector:: operator *( const Vector &) const ; </li></ul><ul><li>с onst Vector Vector:: operator *( const double ) const ; </li></ul><ul><li>с onst Vector operator *( const double, const Vector &); </li></ul><ul><li>// Асоціативність </li></ul><ul><li>Vector u, v, w; </li></ul><ul><li>// ОК </li></ul><ul><li>u* ( v*w ); </li></ul><ul><li>// ОК </li></ul><ul><li>(u*v)*w ; </li></ul>
  29. 29. Вправа <ul><li>Доповніть клас </li></ul><ul><li>class Item </li></ul><ul><li>{ </li></ul><ul><li>private : </li></ul><ul><li>double _price; </li></ul><ul><li>public : </li></ul><ul><li>double operator +( const Item&) const ; </li></ul><ul><li>// Які ще операції додавання потрібні, щоб з їх </li></ul><ul><li>// допомогою додавати ціни одиниць товару? </li></ul><ul><li>// a+(b+c); (a+b)+c; (a+b)+(c+d); </li></ul><ul><li>}; </li></ul>
  30. 30. Конвертори типів <ul><li>Операції перетворення типів </li></ul><ul><li>Для кожного стандартного або програмованого типу можна визначити перетворення до цього типу </li></ul><ul><li>class Time </li></ul><ul><li>{ </li></ul><ul><li>private : </li></ul><ul><li>int _ hours , _ minutes , _ seconds ; </li></ul><ul><li>public: </li></ul><ul><li>// Перетворення часу в секунди </li></ul><ul><li>operator int () const ; </li></ul><ul><li>}; </li></ul>
  31. 31. Реалізація <ul><li>Перетворення типу завжди визначається як метод </li></ul><ul><li>// Перетворення часу, вираженого </li></ul><ul><li>// в годинах, хвилинах і секундах, </li></ul><ul><li>// в секунди </li></ul><ul><li>Time:: operator int () const </li></ul><ul><li>{ </li></ul><ul><li>return _hours*3600 +_minutes*60 +_seconds; </li></ul><ul><li>} </li></ul>
  32. 32. Явний виклик <ul><li>Перетворення типу можна застосувати явно </li></ul><ul><li>Time t(1, 10 , 20 ); </li></ul><ul><li>cout << int ( t )<< endl ; </li></ul><ul><li>cout <<( int ) t << endl ; </li></ul><ul><li>cout<< static_cast < int >(t)<<endl; </li></ul><ul><li>cout<<t. operator int ()<<endl; </li></ul>
  33. 33. Неявний виклик <ul><li>Виклики неявних перетворень генеруються компілятором </li></ul><ul><li>Time t(1,20,35), t1(1,10,20); </li></ul><ul><li>int duration = 10; </li></ul><ul><li>// Компілятор згенерує код для перетворення типу </li></ul><ul><li>// використана операція додавання цілих чисел </li></ul><ul><li>cout<<t+duration<<endl; </li></ul><ul><li>cout<<t+t<<endl; </li></ul><ul><li>cout<<10*t<<endl; </li></ul><ul><li>// Вивід часу не визначено. Що виведе ця команда? </li></ul><ul><li>cout<<t<<endl; </li></ul>
  34. 34. Декілька конверторів <ul><li>class Time </li></ul><ul><li>{ </li></ul><ul><li>private : </li></ul><ul><li>int _ hours , _ minutes , _ seconds ; </li></ul><ul><li>public: </li></ul><ul><li>// Перетворення часу в секунди </li></ul><ul><li>operator int () const ; </li></ul><ul><li>// Перетворення часу в години </li></ul><ul><li>operator double () const ; </li></ul><ul><li>}; </li></ul>
  35. 35. Реалізація <ul><li>// Перетворення часу в дійсне число </li></ul><ul><li>const double Time::hourToDec = 1./3600.; </li></ul><ul><li>Time:: operator double () const </li></ul><ul><li>{ </li></ul><ul><li>return int (* this )*hourToDec; </li></ul><ul><li>} </li></ul>
  36. 36. Неоднозначність <ul><li>При наявності кількох перетворень неявні перетворення можуть виявитися неоднозначними </li></ul><ul><li>// Компілятор діагностує помилки </li></ul><ul><li>// cout<<t1+t2<<endl; </li></ul><ul><li>// cout<<10+t1<<endl; </li></ul><ul><li>// cout<<10.+t1<<endl; </li></ul><ul><li>Вправа. Запропонувати приклад застосування неявного перетворення часу до цілого і до дійсного числа </li></ul>
  37. 37. Конвертуючі конструктори <ul><li>Конструктор класу T з одним параметром деякого типу S можна трактувати як перетворення об'єкту типу S (параметру) до типу Т. </li></ul><ul><li>class S; </li></ul><ul><li>class T </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>// конвертуючий конструктор </li></ul><ul><li>T( const S&); </li></ul><ul><li>} </li></ul>
  38. 38. Явне перетворення <ul><li>Неявне перетворення типу відмінимо за допомогою заборони неявного виклику конвертуючого конструктора explicit </li></ul><ul><li>class S; </li></ul><ul><li>class T </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>// явний конструктор </li></ul><ul><li>explicit T( const S&); </li></ul><ul><li>} </li></ul>
  39. 39. Приклад <ul><li>class TComplex; </li></ul><ul><li>class A Complex </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>AComplex ( const TComplex&); </li></ul><ul><li>}; </li></ul><ul><li>class T Complex </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>TComplex ( const AComplex&); </li></ul><ul><li>}; </li></ul>
  40. 40. Додавання комплексних чисел <ul><li>Адитивні операції визначаємо як утиліти над комплексними числами в алгебраїчній формі </li></ul><ul><li>const AComplex operator + </li></ul><ul><li>( const AComplex& a, const AComplex& b) </li></ul><ul><li>{ </li></ul><ul><li>return AComplex(a.re()+b.re(), a.im()+b.im()); </li></ul><ul><li>} </li></ul>
  41. 41. Множення комплексних чисел <ul><li>Мультиплікативні операції визначаємо як утиліти над комплексними числами в тригонометричній формі </li></ul><ul><li>const TComplex operator * </li></ul><ul><li>( const TComplex& a, const TComplex& b) </li></ul><ul><li>{ </li></ul><ul><li>return TComplex(a.rho()*b.rho(), a.phi()+b.phi()); </li></ul><ul><li>} </li></ul>
  42. 42. Неявні перетворення комплексних чисел <ul><li>AComplex u(1,1); </li></ul><ul><li>TComplex t(1, 0,7853981633974 ); </li></ul><ul><li>cout<<u+u<<u+t<<t+u<<t+t<<endl; </li></ul><ul><li>cout<<u*u<<u*t<<t*u<<t*t<<endl; </li></ul>
  43. 43. Інше додавання комплексних чисел <ul><li>Адитивні операції визначаємо як методи комплексних чисел в алгебраїчній формі </li></ul><ul><li>const AComplex AComplex :: operator + </li></ul><ul><li>( const AComplex& b) const </li></ul><ul><li>{ </li></ul><ul><li>return AComplex(re()+b.re(), im()+b.im()); </li></ul><ul><li>} </li></ul><ul><li>Яке додавання краще? </li></ul>
  44. 44. Множення комплексних чисел <ul><li>Мультиплікативні операції визначаємо методами комплексних чисел в тригонометричній формі </li></ul><ul><li>const TComplex TComplex :: operator * </li></ul><ul><li>( const TComplex& b) const </li></ul><ul><li>{ </li></ul><ul><li>return TComplex (rho()*b.rho(), phi()+b.phi()); </li></ul><ul><li>} </li></ul><ul><li>Яке множення краще? </li></ul>
  45. 45. Неявні перетворення комплексних чисел <ul><li>AComplex u(1,1); </li></ul><ul><li>TComplex t(1, 0,7853981633974 ); </li></ul><ul><li>cout<<u+u<<u+t<<endl; // OK </li></ul><ul><li>// cout<<t+u<<t+t<<endl; ERROR </li></ul><ul><li>//cout<<u*u<<u*t<<<<endl; ERROR </li></ul><ul><li>cout<<t*u<<t*t<<endl; // OK </li></ul><ul><li>* this не допускає неявних перетворень, тому що має тип [const] T * const </li></ul>
  46. 46. Несиметричність параметрів <ul><li>“ Несподівана” несиметричність в типах першого і другого параметру арифметичних операцій може служити серйозним аргументом на користь операцій-утиліт </li></ul>
  47. 47. Операції вводу/виводу <ul><li>Реалізуються утиліти, тому що лише тип другого параметру визначається програмованим класом, тоді як тип першого аргументу належить класам вихідного або вхідного потоків </li></ul><ul><li>ostream& operator <<(ostream &, const Complex &); </li></ul><ul><li>istream& operator >>(istream &, Complex&); </li></ul><ul><li>Вправа . Визначте в класі Complex методи вводу і виводу </li></ul>
  48. 48. Інші програмовані операції <ul><li>Доступ за індексом </li></ul><ul><li>Адресування і розіменування </li></ul><ul><li>Виклик функції </li></ul><ul><li>Інкремент і декремент </li></ul><ul><li>служать підставою для важливих ідіом програмування: асоціативних масивів, інтелектуальних указників, функціональних обєктів </li></ul>

×