МАРК РЕГНЕРУС ДОСЛІДЖЕННЯ: Наскільки відрізняються діти, які виросли в одностатевих союзах
РЕЗОЛЮЦІЯ: Громадського обговорення навчальної програми статевого виховання ЧОМУ ФОНД ОЛЕНИ ПІНЧУК І МОЗ УКРАЇНИ ПРОПАГУЮТЬ "СЕКСУАЛЬНІ УРОКИ" ЕКЗИСТЕНЦІЙНО-ПСИХОЛОГІЧНІ ОСНОВИ ПОРУШЕННЯ СТАТЕВОЇ ІДЕНТИЧНОСТІ ПІДЛІТКІВ Батьківський, громадянський рух в Україні закликає МОН зупинити тотальну сексуалізацію дітей і підлітків Відкрите звернення Міністру освіти й науки України - Гриневич Лілії Михайлівні Представництво українського жіноцтва в ООН: низький рівень культури спілкування в соціальних мережах Гендерна антидискримінаційна експертиза може зробити нас моральними рабами ЛІВИЙ МАРКСИЗМ У НОВИХ ПІДРУЧНИКАХ ДЛЯ ШКОЛЯРІВ ВІДКРИТА ЗАЯВА на підтримку позиції Ганни Турчинової та права кожної людини на свободу думки, світогляду та вираження поглядів Контакти
Тлумачний словник |
|
|||||||
Лекція 17Тема : Перевантаження методів та операторів. При визначенні функцій у своїх програмах ви повинні вказати тип повертається функцією значення, а також кількість параметрів і тип кожного з них. У минулому ( якщо ви програмували на мові С) , коли у вас була функція з ім'ям add_values , яка працювала з двома цілими значеннями , а ви хотіли б використовувати подібну функцію для складання трьох цілих значень , вам слід було створити функцію з іншим ім'ям. Наприклад , ви могли б використовувати add_two_values і add_three_values. Аналогічно якщо ви хотіли використовувати подібну функцію для складання значень типу float , то вам була б необхідна ще одна функція з ще одним ім'ям . Щоб уникнути дублювання функції , C + + дозволяє вам визначати кілька функцій з одним і тим же ім'ям. У процесі компіляції C + + бере до уваги кількість аргументів , що використовуються кожною функцією , і потім викликає саме потрібну опцію. Надання компілятору вибору серед декількох функцій називається перевантаженням . У цьому уроці ви навчитеся використовувати перевантажені функції . До кінця даного уроку ви освоїте такі основні концепції: • Перевантаження функцій дозволяє вам використовувати одне і те ж ім'я для кількох функцій з різними типами параметрів . • Для перевантаження функцій просто визначте дві функції з одним і тим же ім'ям і типом значення, що повертається , які відрізняються кількістю параметрів або їх типом . Перевантаження функцій є особливістю мови C + + , якої немає в мові С. Як ви побачите , перевантаження функцій досить зручна і може поліпшити читабельність ваших програм. ПЕРШЕ ЗНАЙОМСТВО З перевантаження функцій Перевантаження функцій дозволяє вашим програмам визначати кілька функцій з одним і тим же ім'ям і типом значення, що повертається . Наприклад , наступна програма перевантажує функцію з ім'ям add_values . Перше визначення функції складає два значення типу int . Друге визначення функції складає три значення . У процесі компіляції C + + коректно визначає функцію , яку необхідно використовувати: # include <iostream.h> int add_values ( int a , int b ) { int add_values ( int a , int b , int c ) ( void main ( void ) {
Як бачите , програма визначає дві функції з іменами add_values Перша функція складає два значення типу int , в той час як друга складає три значення . Ви не зобов'язані небудь робити спеціально для того , щоб попередити компілятор про перевантаження , просто використовуйте її . Компілятор розгадає , яку функцію слід використовувати , грунтуючись на пропонованих програмою параметрах. Подібним чином наступна програма MSG_OVR.CPP перевантажує функцію show_message . Перша функція з ім'ям show_message виводить стандартне повідомлення , параметри їй не передаються. Друга виводить передане їй повідомлення , а третя виводить два повідомлення : # include <iostream.h> void show_message ( void ) { void show_message ( char * message ) { void show_message ( char * first , char * second ) { void main ( void ) {
КОЛИ ПОТРІБНО Перевантажування Одним з найбільш загальних випадків використання перевантаження є застосування функції для отримання певного результату , виходячи з різних параметрів . Наприклад, припустимо , що у вашій програмі є функція з ім'ям day_of_week , яка повертає поточний день тижня ( 0 для неділі , 1 для понеділка , ... , 6 для суботи). Ваша програма могла б перевантажити цю функцію таким чином , щоб вона вірно повертала день тижня , якщо їй переданий юліанський день в якості параметра , або якщо їй передані день , місяць і рік: int day_of_week ( int julian_day ) { int day_of_week ( int month , int day , int year ) {
У міру вивчення об'єктно -орієнтованого програмування в C + + , представленого в наступних уроках , ви будете використовувати перевантаження функцій для розширення можливостей своїх програм. Перевантаження функцій покращує читабельність програм Перевантаження функцій C + + дозволяє вашим програмам визначати кілька функцій з одним і тим же ім'ям. Перевантажені функції повинні повертати значення однакового типу * , але можуть відрізнятися кількістю і типом параметрів . До появи перевантаження функцій в C + + програмісти мови С повинні були створювати кілька функцій з майже однаковими іменами. На жаль програмісти , бажаючі використовувати такі функції , повинні були пам'ятати , яка комбінація параметрів відповідає якій функції . З іншого боку , перевантаження функцій спрощує завдання програмістів , вимагаючи , щоб вони пам'ятали тільки одне ім'я функції . * Перевантажені функції не зобов'язані повертати значення однакового типу з тієї причини , що компілятор однозначно ідентифікує функцію по її імені і набору її аргументів. Для компілятора функції з однаковими іменами , але різними типами аргументів - різні функції, тому тип значення - прерогатива кожної функції . - Прім.пер . ЩО ВАМ ТРЕБА ЗНАТИ Перевантаження функцій дозволяє вам вказати кілька визначень для однієї і тієї ж функції . У процесі компіляції C + + визначить , яку функцію слід використовувати, грунтуючись на кількості і типі переданих параметрів . З даного уроку ви дізналися, що перевантажувати функції досить просто . З уроку 14 ви дізнаєтеся , як посилання C + + спрощують процес зміни параметрів всередині функцій . Однак, перш ніж перейти до уроку 14 , переконайтеся , що ви вивчили такі основні концепції: Перевантаження функцій надає кілька " поглядів " на одну і ту ж функцію всередині вашої програми . Для перевантаження функцій просто визначте декілька функцій з одним і тим же ім'ям і типом значення, що повертається , які відрізняються тільки кількістю і типом параметрів . У процесі компіляції C + + визначить , яку функцію слід викликати , грунтуючись на кількості і типі переданих параметрів . Перевантаження функцій спрощує програмування , дозволяючи програмістам працювати тільки з одним ім'ям функції . Бажання написати дану статтю з'явилося після прочитання поста Перевантаження C + + операторів , тому що в ньому не було розкрито багато важливі теми . Найголовніше , що необхідно пам'ятати - перевантаження операторів , це всього лише більш зручний спосіб виклику функцій , тому не варто захоплюватися перевантаженням операторів. Використовувати її слід тільки тоді , коли це спростить написання коду. Але , не настільки, щоб це ускладнювало читання . Адже , як відомо , код читається набагато частіше , ніж пишеться . І не забувайте , що вам ніколи не дадуть перевантажити оператори в тандемі з вбудованими типами , можливість перевантаження є тільки для користувача типів / класів .
синтаксис перевантаження Синтаксис перевантаження операторів дуже схожий на визначення функції з ім'ям operator @ , де @ - це ідентифікатор оператора ( наприклад +, - , << , >> ) . Розглянемо найпростіший приклад : class Integer
У даному випадку , оператор оформлений як член класу , аргумент визначає значення, що знаходиться в правій частині оператора. Взагалі , існує два основних способи перевантаження операторів : глобальні функції , дружні для класу , або підставляються функції самого класу. Який спосіб , для якого оператора краще , розглянемо в кінці топіка . У більшості випадків , оператори ( крім умовних ) повертають об'єкт , або посилання на тип , до якого відносяться його аргументи (якщо типи різні, то ви самі вирішуєте як інтерпретувати результат обчислення оператора). Перевантаження унарних операторів Розглянемо приклади перевантаження унарних операторів для певного вище класу Integer . Заодно визначимо їх у вигляді дружніх функцій і розглянемо оператори декремента і инкремента : class Integer {private : / / унарний + / / унарний - / / префіксний інкремент / / постфіксний інкремент / / префіксний декремент / / постфіксний декремент / / унарний плюс нічого не робить. const Integer operator - ( const Integer & i ) { / / префіксная версія повертає значення після инкремента / / Постфіксний версія повертає значення до инкремента / / префіксная версія повертає значення після декремента / / Постфіксний версія повертає значення до декремента Тепер ви знаєте , як компілятор розрізняє префіксние і постфіксні версії декремента і инкремента . У разі , коли він бачить вираз + + i , то викликається функція operator + + ( a ) . Якщо ж він бачить i + + , то викликається operator + + ( a , int ) . Тобто викликається перевантажена функція operator + + , і саме для цього використовується фіктивний параметр int в постфіксной версії.
бінарні оператори Розглянемо синтаксис перевантаження бінарних операторів. Перевантажимо один оператор , який повертає l - значення , один умовний оператор і один оператор , що створює нове значення ( визначимо їх глобально ) : class Integer friend Integer & operator + = ( Integer & left , const Integer & right ) ; friend bool operator == ( const Integer & left , const Integer & right ) ; const Integer operator + ( const Integer & left , const Integer & right ) { Integer & operator + = ( Integer & left , const Integer & right ) { bool operator == ( const Integer & left , const Integer & right ) {
У всіх цих прикладах оператори перевантажуються для одного типу , однак , це необов'язково. Можна, наприклад , перевантажити додавання нашого типу Integer і визначеного за його подобою Float . Аргументи і повертаються значення
Як можна було помітити , в прикладах використовуються різні способи передачі аргументів у функції і повернення значень операторів. Якщо аргумент не змінюється оператором , у випадку, наприклад Унарні плюса , його потрібно передавати як посилання на константу . Взагалі , це справедливо для майже всіх арифметичних операторів (додавання, віднімання , множення ... ) Тип значення залежить від суті оператора. Якщо оператор повинен повертати нове значення , то необхідно створювати новий об'єкт ( як у випадку бінарного плюса ) . Якщо ви хочете заборонити зміну об'єкта як l - value , то потрібно повертати його константним . Оптимізація значення, що повертається При створенні нових об'єктів і повернення їх з функції слід використовувати запис як для вищеописаного прикладу оператора бінарного плюса. return Integer ( left.value + right.value ) ; Чесно кажучи , не знаю , яка ситуація актуальна для C + +11 , всі міркування далі справедливі для C + +98 . На перший погляд , це схоже на синтаксис створення тимчасового об'єкта , тобто начебто б немає різниці між кодом вище і цим: Integer temp ( left.value + right.value ) ;
Але насправді , в цьому випадку відбудеться виклик конструктора в першому рядку, далі виклик конструктора копіювання , який скопіює об'єкт , а далі , при розкручуванні стека викличеться деструктор . При використанні першого запису компілятор спочатку створює об'єкт в пам'яті , в яку потрібно його скопіювати , таким чином економиться виклик конструктора копіювання і деструкції. особливі оператори У C + + є оператори , що володіють специфічним синтаксисом і способом перевантаження. Наприклад оператор індексування []. Він завжди визначається як член класу і , так як мається на увазі поведінку индексируемого об'єкта як масиву , то йому слід повертати посилання . оператор кома У число «особливих» операторів входить також оператор кома . Він викликається для об'єктів , поряд з якими поставлена кома (але він не викликається в списках аргументів функцій). Придумати осмислений приклад використання цього оператора не так-то просто . Хабраюзер AxisPod в коментарях до попередньої статті про перевантаження розповів про одне. Оператор разименованія покажчика Перевантаження цих операторів може бути виправдана для класів розумних покажчиків . Цей оператор обов'язково визначається як функція класу , причому на нього накладаються деякі обмеження : він повинен повертати або об'єкт ( або посилання ), або покажчик , що дозволяє звернутися до об'єкта. оператор присвоювання Оператор присвоювання обов'язково визначається у вигляді функції класу , тому що він нерозривно пов'язаний з об'єктом, що знаходиться зліва від "=" . Визначення оператора привласнення в глобальному вигляді зробило б можливим перевизначення стандартного поведінки оператора " =" . приклад : class Integer Integer & operator = ( const Integer & right ) {
Як можна помітити , на початку функції проводиться перевірка на самопрісваіваніе . Взагалі , в даному випадку самопрісваіваніе нешкідливо , але ситуація не завжди така проста . Наприклад , якщо об'єкт великий , можна витратити багато часу на непотрібне копіювання , або при роботі з покажчиками . Неперегружаемие оператори Деякі оператори в C + + не перевантажуються в принципі. По всій видимості , це зроблено з міркувань безпеки. Оператор вибору члена класу ". " . Оператор разименованія покажчика на член класу ". * " У С + + відсутня оператор піднесення до степеня (як у Fortran ) " ** " . Заборонено визначати свої оператори ( можливі проблеми з визначенням пріоритетів ) . Не можна змінювати пріоритети операторів
Рекомендації до форми визначення операторів Як ми вже з'ясували , існує два способи операторів - у вигляді функції класу і у вигляді дружньої глобальної функції . Роб Мюррей , у своїй книзі C + + Strategies and Tactics визначив наступні рекомендації з вибору форми оператора : Оператор Рекомендована форма Всі унарні оператори член класу = ( ) [] -> -> * Обов'язково член класу + = - = / = * = ^ = & = | = % = >> = << = Решта бінарні оператори Чи не член класу Чому так ? По-перше , на деякі оператори спочатку накладено обмеження . Взагалі , якщо семантично немає різниці як визначати оператор , то краще його оформити у вигляді функції класу , щоб підкреслити зв'язок , плюс крім цього функція буде підставляється ( inline ) . До того ж , іноді може виникнути потреба в тому , щоб представити лівобічний операнд об'єктом іншого класу. Напевно , найяскравіший приклад - перевизначення << і >> для потоків введення / виводу. Література Брюс Еккель - Філософія C + +. Введення в стандартний C + +. Читайте також:
|
||||||||
|