Перевантаження операцій в мові С++
Завантажити презентаціюПрезентація по слайдам:
Перевантаження операцій в мові С++ Клас – це тип даних, визначений програмістом. Коли використовується змінна будь-якого стандартного типу, для неї припустимий певний набір операцій. Мова С++ надає можливості зробити типи, що створюються, тобто класи, максимально наближеними за можливостями до стандартних типів. Зокрема можливо перевизначити (перевантажити) звичні знаки операцій таким чином, щоб вони стосувались екземплярів класів. Наприклад, нехай визначений клас complex, що реалізує комплексне число. Звісно, можна реалізувати дії з екземплярами цього класу як звертання до певних функцій класу, проте значно зручніше було б оперувати звичними для сприйняття виразами на кшталт: complex a, b; complex c = a + b; c = a*b; Вивченню подібних можливостей і присвячений подальший виклад.
1. Дружні функції. Як відомо, доступ до закритих (і захищених) членів класу неможливий із зовнішнього коду. Проте виняток становлять так звані “дружні” функції. Достатньо помістити в класі декларацію зовнішньої функції із службовим словом friend, і вона матиме доступ до всіх без винятку членів класу. class Student { private : char name [20]; // ім’я студента double av_mark; // середній бал double ex_mark; // бал за екзамен // дружня функція friend void excellent (Student &s); public : … }; // Ця функція робить відмінником будь-якого студента void excellent (Student &s) { s.av_mark = 60; s.ex_mark = 40; }
Зауваження про дружні функції. 1. Слід пам'ятати, що функція із модифікатором friend не є членом класу, хоча її декларація і фігурує в класі. 2. Дружня функція має такі самі права доступу до всіх членів класу як і функція-член класу.
2. Вказівник this. Кожна функція-член класу (в тому числі конструктори та деструктор) мають вказівник this. Характерною особливістю його є те, що він вказує на екземпляр, для якого здійснюється виклик. Приклад (продовження). class Student { … }; int main () { Student st1 (30, 30); Student st2 (60, 40, "Ivanov"); cout
Правила перевантаження операцій в класі Для перевантаження операцій використовуються так звані операторні функції – функції із ідентифікатором operator@, де замість знаку @ стоїть знак операції, що перевантажується. При визначенні операторної функції дотримуються спеціальних синтаксичних вимог. По-перше, операторна функція може бути визначена як функція-член класу або як зовнішня дружня функція. По-друге, по-різному визначаються унарні та бінарні операції.
Декларація функції-члену класу для перевантаження бінарної операції: operator@(< тип_операнду_2>); При цьому перший операнд операції передається неявно у вигляді вказівника this, тобто обов’язково має тип классу. Таким чином, для реалізації операції виду a@b, де a та b – екземпляри відповідного класу, відбувається виклик операторної функції: a.operator@ (b) Декларація дружньої функції для перевантаження бінарної операції: friend operator@ (, < тип_операнду_2>); При цьому для реалізації операції виду a@b відбувається виклик операторної функції: operator@ (a,b)
Декларація функції-члену класу для перевантаження унарної операції: operator@ (); При цьому операнд операції передається неявно у вигляді вказівника this, тобто обов’язково має тип классу. Для реалізації операції виду @a відбувається виклик операторної функції: a.operator@ () Декларація дружньої функції для перевантаження унарної операції: friend operator@ (); В цьому випадку для реалізації операції виду @a відбувається виклик операторної функції: operator@ (a)
Особливості використання операції присвоєння операцій. 1. Слід знати, що за умовчанням операція = для двох екземплярів класу здійснює поелементне копіювання даних-членів цих екземплярів. Якщо це саме те, що потрібно для вашого класу, немає необхідності у перевантаженні операції = . 2. Якщо членом класу є вказівник, то за умовчанням відбуватиметься копіювання відповідних вказівників, а не об'єктів, на які вони посилаються (чого, скоріше за все, ви очікуєте при присвоєнні). В такому разі необхідно коректно перевантажити операцію = . 3. Використання параметром такої операторної функції посилання на об'єкт позбавить від створення та знищення у стеку його копії і зекономить ресурси.
Ще один нюанс визначення унарних операцій пов’язаний із операціямии інкременту та декременту. Як відомо, і інкремент, і декремент можуть префіксними або постфіксними (в мові С# вони не розрізнялись). Мова С++ надає можливість реалізувати префіксні та постфіксні операії по-різному. Для цього в операторній функції, що реалізує постфіксні операції, використовується фіктивний параметр. Його наявність дозволяє перевантажити відповідним чином операції: // префіксний інкремент: operator++ (); // постфіксний інкремент: operator++ (int unused); Або, якщо операції визначаються з допомогою дружніх функцій: // префіксний інкремент: friend operator++ (); // постфіксний інкремент: friend operator++ (, int unused); Абсолютно аналогічні правила діють і для операції декременту.
Зауваження про обмеження при перевантаженні операцій. 1. Перевантажена операція класу повинна мати принаймні один операнд з типом даного класу – таким чином забезпечується цілісність операцій зі стандартними типами даних: ви не можете перевантажити операцію + для цілих змінних так, щоб вона реалізовувала, наприклад, віднімання. 2. Перевантажена операція не може змінювати синтаксис існуючих операцій, наприклад операція % не може бути унарною. Так само неможливо змінити пріоритети існуючих операцій. 3. Неможливо створювати нові символи для операцій, наприклад, x**y неможливо реалізувати як піднесення x до степеня y. 4. Не перевантажуються наступні операції: sizeof . (доступ до елементу) * (операція вказівник на елемент) :: (оператор області видимості) ?: (тернарна операція) та деякі інші, пов’язані з приведенням та перетворенням типів.
Зауваження про використання дружніх функцій при перевантаженні операцій. 1. В багатьох випадках не має різниці, яку саме форму операторної функції (функція-член класу чи дружня функція) ви використовуєте. 2. Якщо ж ви намагаєтесь перевантажити деяку операцію, яка буде використовуватись у виразах, де перший операнд не є екземпляром даного класу (скажімо, при множенні скаляра на екземпляр класу, що реалізує вектор або матрицю), то операторна функція обов'язково має бути реалізована як дружня. 3. Більшість операцій можуть бути перевантажені як функції-члени класу, так і з допомогою дружніх функцій. Проте наступні операції можуть перевантажуватись лише з допомогою функцій-членів класу: = (присвоєння) () (оператор виклику функції) [] (оператор індексації) -> (доступ до членів класу через вказівник).
Схожі презентації
Категорії