Бублик Володимир Васильович Процедурне програмування C/C++ Лекція 10. Статичний поліморфізм Лекції для студентів 2 курсу Консультації: середа год., кімн. 204/1, кафедра мультимедійних систем Hamburg, Packhaus
1. Функціональна полісемія Указники функцій
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 3 (38) Непряме звернення до функцій Оголошення указника функції double (*f) (double); Визначення з ініціалізацією double (*f ) (double) = 0; double (*trigon) (double) = sin; Присвоєння trigon = cos;
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 4 (38) Виклик за указником #include int main() { double (*trigon) (double) = sin; cout<<trigon(0)<<endl; trigon = cos; cout<<trigon(0)<<endl; return 0; }
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 5 (38) Масиви указників функцій const int n = 10; double (*g[n]) (double); typedef double (*F) (double); F * pf = new F[n]; g[1] = sin; pf[2] = exp;
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 6 (38) Функціонали Розв'язування рівнянь методом ділення навпіл R x R x R x [R -> R] -> R double Newton (double a, double b, double eps, double (*f) (double)); double Simpson (double a, double b, double eps, double (*f) (double)); В яких випадках бажано або необхідно мати одне спільне позначення для різних дій?
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 7 (38) Спрощений запис Все той же указник... double Newton (double a, double b, double eps, double f (double)); double Simpson (double a, double b, double eps, double f (double)); Чому замість указника на функцію не можна застосувати її ім'я або псевдонім?
2. Розширення області визначення (overloading) функцій Що бракує С?
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 9 (38) Мінімізація понять На всі випадки один символ для додавання Натуральні 1+2// 1 + n 2 Цілі -1+2// -1 + i 2 Раціональні + // + z Дійсні φ + 2 π k// φ + r 2 π k Комплексні (a + bi) + (c + di) // (a bi) (c di) Вектори u+v Матриці A+B
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 10 (38) Однойменні функції Обмін цілих значень void pswap ( int *x, int *y);// стиль С void rswap ( int &x, int &y);// стиль С++ Як назвати цю ж функцію для дійсних (символьних, …) значень? void pswap_char (char *x, char *y);//? void pswap_1 (char *x, char *y);//? Краще всього залишити цю ж назву pswap або відповідно rswap
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 11 (38) Overloading Якщо функція визначається сигнатурою, а не тільки іменем, то кожній сигнатурі приписуємо свою реалізацію void pswap ( int *x, int *y); void pswap ( char *x, char *y); void pswap (double *x, double *y);
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 12 (38) Виклики Якщо функція визначається сигнатурою, а не тільки іменем, то за типами фактичних параметрів можна встановити, функція якої саме сигнатури викликається char a, b; int m, n; float x, y; pswap (&a, &b); pswap (&m, &n); pswap (&x, &y);
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 13 (38) Перший висновок Якщо функція визначається сигнатурою, а не тільки іменем, то немає більше необхідності в різних іменах pswap і rswap для функцій swap, що різнитимуться типами параметрів: указниками та відсилками void swap ( int &x, int &y); void swap ( int *x, int *y); Але для сигнатури void swap ( int x, int y); вже немає місця (чому?)
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 14 (38) Функції swap: різні способи передачі параметрів void swap ( int *x, int *y) { int z=*x; *x=*y; *y=z; return; } void swap ( int &x, int &y) { int z=x; x=y; y=z; }
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 15 (38) Функції swap: різні типи даних void swap (double *x, double *y) { double z=*x; *x=*y; *y=z; return; } void swap (double &x, double &y) { double z=x; x=y; y=z; return; }
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 16 (38) Функції swap: різні реалізації void swap ( int *x, int *y) { *x=*x+*y; *y=*x-*y;*x=*x-*y; return; } void swap ( int &x, int &y) { x=x+y; y=x-y; x=x-y; return; }
3. Розширення області визначення (overloading) операцій Що ще бракує С?
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 18 (38) Довизначені операції struct Point { double _x; double _y; }; const Point plus(Point u, Point v) //дуже незграбно { Point res; res._x = u._x+v._x; res._y = u._y+v._y; return res; }
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 19 (38) Так краще int main() { const Point one_zero = {1, 0}; Point u = {2, 3}; Point v = u + one_zero; cout<<v._x<<v._y<<endl; return 0; }
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 20 (38) Так ще краще int main() { const Point one = {1, 0}; Point u = {2, 3}; Point v = u + one; cout<<v<<endl; return 0; }
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 21 (38) Або навіть int main() { const Point one_zero = {1, 0}; Point u = {2, 3}; cout<< u + one_zero <<endl; return 0; }
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 22 (38) Point.h //Arithmetic const Point operator+ (const Point &, const Point &); //Варіація //Point operator+ (Point, Point); //Boolean bool operator== (const Point &, const Point &); //Input-output ostream& operator<<(ostream &os, const Point &); istream& operator>>(istream &is, Point &);
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 23 (38) Погодження Замість plus (u, v); або operator+(u, v); Пишемо u+v; Відповідно замість суперпозиції operator+(u, operator+(v, w)); звичайний запис u+v+w;
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 24 (38) Point.cpp const Point operator+(const Point & u, const Point & v) { Point res = {u._x+v._x, u._y+v._y}; return res; } bool operator==(const Point& u, const Point & v) { return (u._x == v._x) && (u._y == v._y); }
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 25 (38) Point.cpp ostream& operator<<(ostream &os, const Point& u) { os<<'('<<u._x<<','<<u._y<<')'; return os; } istream& operator>>(istream &is, Point& u) { is>>u._x>>u._y; return is; }
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 26 (38) Змішані типи struct Complex { double _re; double _im; }; //Arithmetic const Complex operator+ (const Complex &, const Complex &); const Complex operator+ (double, const Complex &); const Complex operator+ (const Complex &, double);
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 27 (38) Змішані типи const Complex i = {0, 1}; Complex z = {1, 1}; double x = 2, y=3; cout << (x +5) + (z+i) + y<<endl; Complex operator+ (const Complex &, const Complex &); Complex operator+ (double, const Complex &); Complex operator+ (const Complex &, double); ostream& operator<<(ostream &os, const Complex &); Як визначити одне додавання для всіх? (далі буде)
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 28 (38) Множення struct WrappedVector { static const int n; double * x; }; double operator* (const WrappedVector&, const WrappedVector&); Або (але не одночасно, чому?) const WrappedVector operator* (const WrappedVector&, const WrappedVector&);
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 29 (38) Зауваження до const Несталий результат Complex operator+ (const Complex &, const Complex &); породжує безглуздий код: u+v=w; Сталий результат захищений від безглуздого вжитку const Complex operator+ (const Complex &, const Complex &); // ERROR u+v=w;
4. Узагальнені функції (function template)
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 31 (38) Мінімізація текстів void swap ( int &x, int &y); void swap ( char &x, char &y); void swap ( double &x, double &y); Записати три і більше реалізацій одним текстом
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 32 (38) Myswap.h Куди помістити? template void myswap (T &x, T &y) { T z = x; x = y; y = z; return; } Чому не Myswap.сpp?
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 33 (38) Myswap.cpp int m=10, n=20; myswap (m, n); double a=1.25, b = 2.50; myswap (a, b); Point u ={1,2}, v={3,4}; myswap(u,v); Complex z1 = {1,1}, z2 = {2,2}; myswap (z1, z2);
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 34 (38) Конкретизація int m=10, n=20; short k=50, i=40; myswap (m, n); myswap (i, k); //Звичайна функція void myswap ( int &x, int &y) { cout<<"Non template"<<endl; x=x+y; y=x-y; x=x-y; }
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 35 (38) Союз довизначень і узагальнень Для типу Т повинні бути визначені всі функції і операції, вжиті в узагальненій функції template T max(T x, Ty) { return (x>y)?x:y; }
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 36 (38) Союз довизначень і узагальнень int m=10, n=20; cout<<max (m, n)<<endl; double a=1.25, b = 2.50; cout<<max (a, b) <<endl; Point u ={1,2}, v={3,4}; // max (u,v);ERROR Complex z1 = {1,1}, z2 = {2,2}; // max (z1, z2); ERROR
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 37 (38) Узагальнення в даних template struct WrappedVector { T *_v; static size_t n; }; template T operator* (const WrappedVector &, const WrappedVector &);
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 38 (38) Складність компіляції Вибір функції за типами фактичних параметрів з урахуванням можливих перетворень типів, використання замовчуваних значень параметрів, можливостей конкретизації шаблонів. В деяких випадках компілятор не справляється з однозначним визначенням потрібної функції
© Бублик В.В. Процедурне програмування -11. Статичний поліморфізм 39 (38) Висновок Поліморфізм полягає у використанні об'єктів, що можуть набувати багатьох різних типів. При динамічному поліморфізмі тип об'єкта визначиться лише на етапі виконання (далі буде). Статичний поліморфізм це визначення типів, використаних узагальненою функцією, на етапі компіляції з одночасною конкретизацією шаблону або вибором підходящої звичайної функції. Конкретизація можлива, якщо всі вирази шаблону визначені для конкретизуючого типу