Студопедия
Новини освіти і науки:
МАРК РЕГНЕРУС ДОСЛІДЖЕННЯ: Наскільки відрізняються діти, які виросли в одностатевих союзах


РЕЗОЛЮЦІЯ: Громадського обговорення навчальної програми статевого виховання


ЧОМУ ФОНД ОЛЕНИ ПІНЧУК І МОЗ УКРАЇНИ ПРОПАГУЮТЬ "СЕКСУАЛЬНІ УРОКИ"


ЕКЗИСТЕНЦІЙНО-ПСИХОЛОГІЧНІ ОСНОВИ ПОРУШЕННЯ СТАТЕВОЇ ІДЕНТИЧНОСТІ ПІДЛІТКІВ


Батьківський, громадянський рух в Україні закликає МОН зупинити тотальну сексуалізацію дітей і підлітків


Відкрите звернення Міністру освіти й науки України - Гриневич Лілії Михайлівні


Представництво українського жіноцтва в ООН: низький рівень культури спілкування в соціальних мережах


Гендерна антидискримінаційна експертиза може зробити нас моральними рабами


ЛІВИЙ МАРКСИЗМ У НОВИХ ПІДРУЧНИКАХ ДЛЯ ШКОЛЯРІВ


ВІДКРИТА ЗАЯВА на підтримку позиції Ганни Турчинової та права кожної людини на свободу думки, світогляду та вираження поглядів



Контакти
 


Тлумачний словник
Авто
Автоматизація
Архітектура
Астрономія
Аудит
Біологія
Будівництво
Бухгалтерія
Винахідництво
Виробництво
Військова справа
Генетика
Географія
Геологія
Господарство
Держава
Дім
Екологія
Економетрика
Економіка
Електроніка
Журналістика та ЗМІ
Зв'язок
Іноземні мови
Інформатика
Історія
Комп'ютери
Креслення
Кулінарія
Культура
Лексикологія
Література
Логіка
Маркетинг
Математика
Машинобудування
Медицина
Менеджмент
Метали і Зварювання
Механіка
Мистецтво
Музика
Населення
Освіта
Охорона безпеки життя
Охорона Праці
Педагогіка
Політика
Право
Програмування
Промисловість
Психологія
Радіо
Регилия
Соціологія
Спорт
Стандартизація
Технології
Торгівля
Туризм
Фізика
Фізіологія
Філософія
Фінанси
Хімія
Юриспунденкция






Лекція 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 )

{
return ( a + b ) ;
)

int add_values ( int a , int b , int c )

(
return ( a + b + c ) ;
)

void main ( void )

{
cout << " 200 + 801 = " << add_values ( 200 , 801) << endl ;
cout << " 100 + 201 + 700 = " << add_values (100, 201 , 700 ) << endl ;
}

 

Як бачите , програма визначає дві функції з іменами add_values ​​Перша функція складає два значення типу int , в той час як друга складає три значення . Ви не зобов'язані небудь робити спеціально для того , щоб попередити компілятор про перевантаження , просто використовуйте її . Компілятор розгадає , яку функцію слід використовувати , грунтуючись на пропонованих програмою параметрах.

Подібним чином наступна програма MSG_OVR.CPP перевантажує функцію show_message . Перша функція з ім'ям show_message виводить стандартне повідомлення , параметри їй не передаються. Друга виводить передане їй повідомлення , а третя виводить два повідомлення :

# include <iostream.h>

void show_message ( void )

{
cout << " Стандартне повідомлення : " << " Вчимося програмувати на C + + " << endl ;
}

void show_message ( char * message )

{
cout << message << endl ;
}

void show_message ( char * first , char * second )

{
cout << first << endl ;
cout << second << endl ;
}

void main ( void )

{
show_message ();
show_message ( "Вчимося програмувати на мові C + +! " ) ;
show_message ( " B C + + немає забобонів ! " , " Перевантаження - це круто !") ;
}

 

КОЛИ ПОТРІБНО Перевантажування

Одним з найбільш загальних випадків використання перевантаження є застосування функції для отримання певного результату , виходячи з різних параметрів . Наприклад, припустимо , що у вашій програмі є функція з ім'ям 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
{
private :
int value ;
public :
Integer ( int i ) : value ( i )
{ }
const Integer operator + ( const Integer & rv ) const {
return ( value + rv.value ) ;
}
} ;

 

У даному випадку , оператор оформлений як член класу , аргумент визначає значення, що знаходиться в правій частині оператора. Взагалі , існує два основних способи перевантаження операторів : глобальні функції , дружні для класу , або підставляються функції самого класу. Який спосіб , для якого оператора краще , розглянемо в кінці топіка .

У більшості випадків , оператори ( крім умовних ) повертають об'єкт , або посилання на тип , до якого відносяться його аргументи (якщо типи різні, то ви самі вирішуєте як інтерпретувати результат обчислення оператора).

Перевантаження унарних операторів

Розглянемо приклади перевантаження унарних операторів для певного вище класу Integer . Заодно визначимо їх у вигляді дружніх функцій і розглянемо оператори декремента і инкремента :

class Integer

{private :
int value ;
public :
Integer ( int i ) : value ( i )
{ }

/ / унарний +
friend const Integer & operator + ( const Integer & i ) ;

/ / унарний -
friend const Integer operator - ( const Integer & i ) ;

/ / префіксний інкремент
friend const Integer & operator + + ( Integer & i ) ;

/ / постфіксний інкремент
friend const Integer operator + + ( Integer & i , int ) ;

/ / префіксний декремент
friend const Integer & operator - ( Integer & i ) ;

/ / постфіксний декремент
friend const Integer operator - ( Integer & i , int ) ;
} ;

/ / унарний плюс нічого не робить.
const Integer & operator + ( const Integer & i ) {
return i.value ;
}

const Integer operator - ( const Integer & i ) {
return Integer ( - i.value ) ;
}

/ / префіксная версія повертає значення після инкремента
const Integer & operator + + ( Integer & i ) {
i.value + +;
return i ;
}

/ / Постфіксний версія повертає значення до инкремента
const Integer operator + + ( Integer & i , int ) {
Integer oldValue ( i.value ) ;
i.value + +;
return oldValue ;
}

/ / префіксная версія повертає значення після декремента
const Integer & operator - ( Integer & i ) {
i.value - - ;
return i ;
}

/ / Постфіксний версія повертає значення до декремента
const Integer operator - ( Integer & i , int ) {
Integer oldValue ( i.value ) ;
i.value - - ;
return oldValue ;
}

Тепер ви знаєте , як компілятор розрізняє префіксние і постфіксні версії декремента і инкремента . У разі , коли він бачить вираз + + i , то викликається функція operator + + ( a ) . Якщо ж він бачить i + + , то викликається operator + + ( a , int ) . Тобто викликається перевантажена функція operator + + , і саме для цього використовується фіктивний параметр int в постфіксной версії.

 

бінарні оператори

Розглянемо синтаксис перевантаження бінарних операторів. Перевантажимо один оператор , який повертає l - значення , один умовний оператор і один оператор , що створює нове значення ( визначимо їх глобально ) :

class Integer
{
private :
int value ;
public :
Integer ( int i ) : value ( i )
{ }
friend const Integer operator + ( const Integer & left , const Integer & right ) ;

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 ) {
return Integer ( left.value + right.value ) ;
}

Integer & operator + = ( Integer & left , const Integer & right ) {
left.value + = right.value ;
return left ;
}

bool operator == ( const Integer & left , const Integer & right ) {
return left.value == right.value ;
}

 

У всіх цих прикладах оператори перевантажуються для одного типу , однак , це необов'язково. Можна, наприклад , перевантажити додавання нашого типу Integer і визначеного за його подобою Float .

Аргументи і повертаються значення

 

Як можна було помітити , в прикладах використовуються різні способи передачі аргументів у функції і повернення значень операторів.

Якщо аргумент не змінюється оператором , у випадку, наприклад Унарні плюса , його потрібно передавати як посилання на константу . Взагалі , це справедливо для майже всіх арифметичних операторів (додавання, віднімання , множення ... )

Тип значення залежить від суті оператора. Якщо оператор повинен повертати нове значення , то необхідно створювати новий об'єкт ( як у випадку бінарного плюса ) . Якщо ви хочете заборонити зміну об'єкта як l - value , то потрібно повертати його константним .
Для операторів присвоювання необхідно повертати посилання на змінений елемент . Також , якщо ви хочете використовувати оператор присвоєння в конструкціях виду ( x = y ) . F ( ) , де функція f ( ) викликається для для змінної x , після присвоювання їй y , то чи не повертайте посилання на константу , повертайте просто посилання .
Логічні оператори повинні повертати в гіршому випадку int , а в кращому bool .

Оптимізація значення, що повертається

При створенні нових об'єктів і повернення їх з функції слід використовувати запис як для вищеописаного прикладу оператора бінарного плюса.

return Integer ( left.value + right.value ) ;

Чесно кажучи , не знаю , яка ситуація актуальна для C + +11 , всі міркування далі справедливі для C + +98 .

На перший погляд , це схоже на синтаксис створення тимчасового об'єкта , тобто начебто б немає різниці між кодом вище і цим:

Integer temp ( left.value + right.value ) ;
return temp ;

 

Але насправді , в цьому випадку відбудеться виклик конструктора в першому рядку, далі виклик конструктора копіювання , який скопіює об'єкт , а далі , при розкручуванні стека викличеться деструктор . При використанні першого запису компілятор спочатку створює об'єкт в пам'яті , в яку потрібно його скопіювати , таким чином економиться виклик конструктора копіювання і деструкції.

особливі оператори

У C + + є оператори , що володіють специфічним синтаксисом і способом перевантаження. Наприклад оператор індексування []. Він завжди визначається як член класу і , так як мається на увазі поведінку индексируемого об'єкта як масиву , то йому слід повертати посилання .

оператор кома

У число «особливих» операторів входить також оператор кома . Він викликається для об'єктів , поряд з якими поставлена ​​кома (але він не викликається в списках аргументів функцій). Придумати осмислений приклад використання цього оператора не так-то просто . Хабраюзер AxisPod в коментарях до попередньої статті про перевантаження розповів про одне.

Оператор разименованія покажчика

Перевантаження цих операторів може бути виправдана для класів розумних покажчиків . Цей оператор обов'язково визначається як функція класу , причому на нього накладаються деякі обмеження : він повинен повертати або об'єкт ( або посилання ), або покажчик , що дозволяє звернутися до об'єкта.

оператор присвоювання

Оператор присвоювання обов'язково визначається у вигляді функції класу , тому що він нерозривно пов'язаний з об'єктом, що знаходиться зліва від "=" . Визначення оператора привласнення в глобальному вигляді зробило б можливим перевизначення стандартного поведінки оператора " =" . приклад :

class Integer
{
private :
int value ;
public :
Integer ( int i ) : value ( i )
{ }

Integer & operator = ( const Integer & right ) {
/ / перевірка на самопрісваіваніе
if ( this == & right ) {
return * this ;
}
value = right.value ;
return * this ;
}
} ;

 

Як можна помітити , на початку функції проводиться перевірка на самопрісваіваніе . Взагалі , в даному випадку самопрісваіваніе нешкідливо , але ситуація не завжди така проста . Наприклад , якщо об'єкт великий , можна витратити багато часу на непотрібне копіювання , або при роботі з покажчиками .

Неперегружаемие оператори

Деякі оператори в C + + не перевантажуються в принципі. По всій видимості , це зроблено з міркувань безпеки.

Оператор вибору члена класу ". " .

Оператор разименованія покажчика на член класу ". * "

У С + + відсутня оператор піднесення до степеня (як у Fortran ) " ** " .

Заборонено визначати свої оператори ( можливі проблеми з визначенням пріоритетів ) .

Не можна змінювати пріоритети операторів

 

Рекомендації до форми визначення операторів

Як ми вже з'ясували , існує два способи операторів - у вигляді функції класу і у вигляді дружньої глобальної функції .

Роб Мюррей , у своїй книзі C + + Strategies and Tactics визначив наступні рекомендації з вибору форми оператора :

Оператор

Рекомендована форма

Всі унарні оператори

член класу

= ( ) [] -> -> *

Обов'язково член класу

+ = - = / = * = ^ = & = | = % = >> = << =
член класу

Решта бінарні оператори

Чи не член класу

Чому так ? По-перше , на деякі оператори спочатку накладено обмеження . Взагалі , якщо семантично немає різниці як визначати оператор , то краще його оформити у вигляді функції класу , щоб підкреслити зв'язок , плюс крім цього функція буде підставляється ( inline ) . До того ж , іноді може виникнути потреба в тому , щоб представити лівобічний операнд об'єктом іншого класу. Напевно , найяскравіший приклад - перевизначення << і >> для потоків введення / виводу.

Література Брюс Еккель - Філософія C + +. Введення в стандартний C + +.


Читайте також:

  1. Вид заняття: лекція
  2. Вид заняття: лекція
  3. Вид заняття: лекція
  4. Вид заняття: лекція
  5. Вид заняття: лекція
  6. Вступна лекція
  7. Вступна лекція 1. Методологічні аспекти технічного регулювання у
  8. Клітинна селекція рослин.
  9. Колекція фонограм з голосами осіб, які анонімно повідомляли про загрозу вибуху
  10. ЛЕКЦІЯ (4): Мануфактурний період світової економіки
  11. Лекція - Геополітика держави на міжнародній арені
  12. Лекція 02.04.2013




Переглядів: 671

<== попередня сторінка | наступна сторінка ==>
Лекція 16 | Лекція 18

Не знайшли потрібну інформацію? Скористайтесь пошуком google:

 

© studopedia.com.ua При використанні або копіюванні матеріалів пряме посилання на сайт обов'язкове.


Генерація сторінки за: 0.009 сек.