Я не розумію аргументів проти перевантаження оператора [закрито]


82

Я щойно прочитав одну із статей Джоеля, в якій він говорить:

Взагалі, я повинен визнати, що я трохи боюся мовних особливостей, які приховують речі . Коли ви бачите код

i = j * 5;

... в C ви знаєте, щонайменше, що j множується на п'ять, а результати зберігаються в i.

Але якщо ви побачите той самий фрагмент коду в C ++, ви нічого не знаєте. Нічого. Єдиний спосіб дізнатися, що насправді відбувається в C ++, - це з’ясувати, які типи i та j є, що може бути декларовано десь взагалі. Це тому, що j може бути типу, який operator*перевантажив, і він робить щось надзвичайно дотепне, коли ви намагаєтесь його примножити.

(Наголос мій.) Бояться мовних особливостей, які приховують речі? Як можна цього злякатися? Чи не приховування речей (також відомих як абстракція ) є однією з ключових ідей об’єктно-орієнтованого програмування? Щоразу, коли ви викликаєте метод a.foo(b), ви не маєте уявлення про те, що це може зробити. Ви повинні з'ясувати , які типи aі bє, то , що може бути оголошена де - то зовсім інше. Тож чи варто відмовлятися від об'єктно-орієнтованого програмування, оскільки воно приховує занадто багато речей від програміста?

І чим j * 5відрізняється від того j.multiply(5), що вам, можливо, доведеться писати мовою, яка не підтримує перевантаження оператора? Знову ж таки, вам доведеться з’ясувати тип jі заглянути всередину multiplyметоду, тому що ось і ось, jможе бути такого типу, який має multiplyметод, який робить щось надзвичайно дотепне.

"Муахаха, я злий програміст, який називає метод multiply, але те, що він насправді робить, є абсолютно незрозумілим і неінтуїтивним і не має нічого спільного з множенням речей". Це сценарій, який ми повинні враховувати при розробці мови програмування? Тоді нам доведеться відмовитися від ідентифікаторів з мов програмування на тій підставі, що вони можуть вводити в оману!

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

Будь ласка, просвіти мене.


20
+1: Добре написана, добре аргументована, цікава тема та дуже дискусійна. Яскравий приклад питання p.se.
Аллон Гуралнек

19
+1: Люди слухають Джоела Спольського, тому що він добре пише і добре знає. Але це не робить його правильним у 100% часу. Я згоден з вашим аргументом. Якби ми всі дотримувалися логіки Джоела тут, ми нікуди не дінемося.
Ніхто

5
Я заперечую, що або i, і J оголошуються локально, тому ви можете швидко побачити їх тип, або вони є придатними іменами змінних і їх слід перейменовувати належним чином.
Камерон Макфарланд

5
+1, але не забувайте найкращу частину статті Джоеля: після пробіжки марафону до правильної відповіді він без видимих ​​причин зупиняється на 50 футів від нього. Неправильний код не повинен виглядати невірно; вона не повинна компілюватись.
Ларрі Коулман

3
@Larry: Ви можете зробити неправильний компіляцію коду шляхом відповідного визначення класів, тому в його прикладі ви могли мати SafeString і UnsafeString у C ++ або RowIndex і ColumnIndex, але тоді вам доведеться використовувати перевантаження оператора, щоб змусити їх вести себе інтуїтивно.
Девід Торнлі

Відповіді:


32

Абстракція «приховує» код, тому вам не потрібно перейматися внутрішніми роботами, і часто ви не можете їх змінити, але намір не був перешкоджати вам дивитися на це. Ми просто робимо припущення щодо операторів і, як сказав Джоел, це може бути де завгодно. Наявність функції програмування, яка вимагає встановлення всіх перевантажених операторів у певному місці, може допомогти її знайти, але я не впевнений, що це полегшить її використання.

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


13
+1 Біт "Я не бачу". Мовні функції є для використання, а не для зловживань.
Майкл К

5
Тим не менш, у нас є <<оператор, визначений в потоках, який не має нічого спільного з побітним зсувом, прямо в стандартній бібліотеці C ++.
Малькольм

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

1
* також використовується для перенаправлення (як це роблять розумні покажчики та ітератори); незрозуміло, де поставити межу між доброю і поганою перевантаженням
мартінкунев

Це було б не де-небудь, це було б у визначенні типу j.
Енді

19

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

Наприклад, це має сенс перевантажувати +або *оператор для class Matrixабо class Complex. Всі миттєво дізнаються, що це означає. З іншого боку, для мене той факт, що +означає об'єднання рядків, зовсім не очевидний, навіть якщо Java робить це як частину мови, а STL робить для std::stringвикористання перевантаження оператора.

Ще одним хорошим прикладом, коли перевантаження оператора робить код більш зрозумілим, - це смарт-покажчики на C ++. Ви хочете, щоб розумні покажчики якомога більше поводилися як звичайні вказівники, тому має сенс перевантажувати одинаків *та ->операторів.

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


1
Ваші останні два речення потрапляють до основи заперечення щодо перевантаження оператора: прагнення, щоб весь код був негайно очевидним.
Ларрі Коулман

2
Чи не очевидно, що означає M * N, де M і N - матриця типу?
Діма

2
@Fred: Ні. Існує один вид множення матриць. Ви можете помножити матрицю mxn на матрицю nxk і отримати матрицю mxk.
Діма

1
@FredOverflow: Існують різні способи множення тривимірного вектора, один дає вам скаляр, а інший - тривимірний вектор, і тому перевантаження *для них може спричинити плутанину. Можливо, ви можете використовувати operator*()для точкового продукту та operator%()для крос-продукту, але я б не робив цього для бібліотеки загального користування.
Девід Торнлі

2
@Martin Beckett: Ні. C ++ заборонено проводити впорядкування, A-Bяк B-Aі всі оператори дотримуються цієї схеми. Хоча завжди є один виняток: коли компілятор може довести, що це не має значення, дозволено все переставити.
Sjoerd

9

У Haskell "+", "-", "*", "/" тощо - це лише (інфікс) функції.

Чи слід називати функцію інфіксації "плюс", як у "4 плюс 2"? Чому б і ні, якщо доповнення - це те, що робить ваша функція. Чи маєте ви назвати свою функцію "плюс" "+"? Чому ні.

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

EDIT: я зробив більш чіткий погляд


Erm, за винятком того, що успадковано від C, C ++ (і саме про це запитував Фред) робить майже те саме. Тепер, що ти сприймаєш, добре це чи погано?
sbi

@sbi Я люблю перевантажувати оператор ... На насправді , навіть C має перевантажені оператори ... Ви можете використовувати їх для int, float, long longі що завгодно. То про що це все?
FUZxxl

@FUZxxl: Це все про визначені користувачем оператори, які перевантажують вбудовані.
sbi

1
@sbi Haskell не має різниці між вбудованим та визначеним користувачем . Усі оператори рівні. Ви навіть можете ввімкнути деякі розширення, щоб видалити всі попередньо задані речі та дозволити вам писати що-небудь з нуля, включаючи будь-які оператори.
FUZxxl

@FUZxxl: Це може бути, але ті, хто виступає проти перевантажених операторів, зазвичай не проти використовувати вбудований +для різних типів вбудованих чисел, а створюють визначені користувачем перевантаження. звідси мій коментар.
sbi

7

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

Це трагічно з двох причин:

  1. Дотримуючись логічного завершення, принцип, що код повинен бути відразу очевидним, мав би нас усіх все ще кодувати в COBOL.
  2. Ви не вчитеся з коду, який відразу очевидний. Ви дізнаєтесь з коду, який має сенс, як тільки знадобиться певний час, щоб подумати, як він працює.

Навчання за допомогою коду не завжди є основною метою. У випадку типу "блискуча функція X", людина, яка її написала, покинула компанію, і вам потрібно це виправити як можна швидше ", я б швидше мав код, який відразу очевидний.
Errorsatz

5

Я дещо згоден.

Якщо ви пишете multiply(j,5), jможе бути скалярного чи матричного типу, що робить multiply()більш-менш складним, залежно від того, що jє. Однак, якщо ви взагалі відмовитеся від ідеї перевантажувати, то функція повинна була б бути названа multiply_scalar()або multiply_matrix()яка б дала зрозуміти, що відбувається внизу.

Є код, де багато хто з нас вважає за краще це в один бік, і є код, де більшість з нас вважає за краще інший спосіб. Однак більша частина коду потрапляє в середнє місце між цими двома крайнощами. Що ви віддаєте перевагу, залежить від вашого фону та особистих уподобань.


Влучне зауваження. Однак відмова від перевантаження взагалі не грає добре із загальним програмуванням ...
fredoverflow

@FredO: Звичайно, ні. Але загальне програмування - це використання одного і того ж алгоритму для дуже різних типів, тому тим, хто віддає перевагу multiply_matrix(), не сподобається і загальне програмування.
sbi

2
Ви досить оптимістично ставитесь до імен, чи не так? Базуючись на деяких місцях, де я працював, я очікував таких імен, як "множити ()` і "помножити ()` або, можливо, real_multiply()чи так. Розробники часто не добре підходять до імен, і, operator*()принаймні, це буде послідовно.
Девід Торнлі

@David: Так, я пропустив через те, що імена можуть бути поганими. Але тоді ми можемо так само припустити, що це operator*()може зробити щось дурне, jце макрос, що оцінює вирази, що включають п'ять викликів функцій, і нічого подібного. Тоді ви вже не можете порівняти два підходи. Але, так, називати речі добре важко, хоча і варто, скільки часу потрібно.
sbi

5
@David: А оскільки називати речі важко, імена повинні бути вилучені з мов програмування, правда? Зробити їх неправильно просто! ;-)
fredoverflow

4

Я бачу дві проблеми з перевантаженням оператора.

  1. Перевантаження змінює семантику оператора, навіть якщо це не призначено програмістом. Наприклад, коли ви перевантажуєтесь &&, ||або ,ви втрачаєте точки послідовності, що маються на увазі вбудованими варіантами цих операторів (а також короткою схемою поведінки логічних операторів). З цієї причини краще не перевантажувати цих операторів, навіть якщо мова це дозволяє.
  2. Деякі люди бачать перевантаження оператора як таку приємну особливість, вони починають використовувати її скрізь, навіть якщо це не відповідне рішення. Це змушує інших людей надмірно реагувати в іншому напрямку та застерігає від використання перевантаження оператора. Я не погоджуюся ні з однією з груп, але візьміть середнє місце: Перевантаження оператора повинна використовуватися вкрай і лише тоді
    • перевантажений оператор має природне значення як для доменних експертів, так і для програмних експертів. Якщо ці дві групи не погоджуються з природним значенням для оператора, не перевантажуйте його.
    • для відповідних типів (типів) не існує природного значення для оператора, а безпосередній контекст (бажано, той самий вираз, але не більше кількох рядків) завжди дає зрозуміти, яке значення має оператор. Прикладом цієї категорії можуть бути operator<<потоки.

1
+1 від мене, але другий аргумент однаково добре можна застосувати і до спадкування. Багато людей не мають поняття про спадщину і намагаються застосувати це до всього. Я думаю, що більшість програмістів погодиться з тим, що спадщину можна зловживати неправильно. Чи означає це успадкування "злим", і його слід відмовитися від мов програмування? Або ми повинні залишити його, бо він також може бути корисним?
fredoverflow

@FredOverflow Другий аргумент можна застосувати до всього, що є "новим та гарячим". Я не даю це як аргумент, щоб зняти перевантаження оператора з мови, але як причину, чому люди сперечаються проти цього. Наскільки я переживаю, перевантаження оператора корисна, але її слід використовувати обережно.
Барт ван Іґен Шенау

IMHO, допускаючи перевантаження &&і ||таким чином, що не передбачає послідовності, було великою помилкою (IMHO, якщо C ++ збирався дозволити перевантажувати їх, він повинен був використовувати спеціальний "двофункціональний" формат, коли перша функція потрібна повернути тип, який неявно перетворювався на ціле число; друга функція може приймати два-три аргументи, при цьому "додатковий" аргумент другої функції є типом повернення першої. Компілятор викликав би першу функцію, а потім, якщо він повернувся не нульовим, оцініть другий операнд і викликайте на ньому другу функцію.)
supercat

Звичайно, це не настільки химерно, як дозволяти перезавантажувати оператор комами. Між іншим, одне, що я дуже перевантажував, я не бачив, але хотів би - це засіб жорсткого зв’язку доступу членів, що дозволяє виразів, як foo.bar[3].Xкерувати fooкласом, а не вимагати fooвикриття члена, який може підтримати підписку, а потім викрити учасника X. Якби хтось хотів змусити оцінку через фактичний доступ учасників, можна написати ((foo.bar)[3]).X.
supercat

3

Виходячи з мого особистого досвіду, спосіб Java, що дозволяє використовувати декілька методів, але не перевантажувати оператора, означає, що кожного разу, коли ви бачите оператора, ви точно знаєте , що він робить.

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

Іншими словами, заборона перевантаження операторів - це користь для читача , а не для автора , а отже, спрощує підтримку програм!


+1, із застереженням: C ++ дає достатню кількість мотузки, щоб повіситись. Але якщо я хочу реалізувати зв'язаний список у C ++, я б хотів мати можливість використовувати [] для доступу до n-го елемента. Має сенс використовувати оператори для даних, для яких (математично кажучи) вони дійсні.
Майкл К

@Michael, ти не можеш жити з list.get(n)синтаксисом?

@ Thorbjørn: Це теж насправді добре, можливо, поганий приклад. Час може бути кращим - перевантаження +, - матиме сенс, а не time.add (anotherTime).
Майкл К

4
@Michael: Що стосується пов'язаних списків, std::listне перевантажує operator[](або не дає інших засобів індексації до списку), оскільки така операція була б O (n), а інтерфейс списку не повинен піддавати такій функції, якщо ви дбаєте про ефективність. Клієнти можуть спокуситися переглядати пов'язані списки з індексами, роблячи алгоритми O (n) без потреби O (n ^ 2). Ви бачите, що це досить часто в Java-коді, особливо якщо люди працюють з Listінтерфейсом, який спрямований на те, щоб повністю абстрагувати складність.
fredoverflow

5
@Thor: "Але для того, щоб бути впевненим, ви повинні перевірити :)" ... Знову ж таки, це не пов'язано з перевантаженням оператора . Якщо ви бачите time.add(anotherTime), вам також доведеться перевірити, чи програміст бібліотеки реалізував операцію додавання "правильно" (що б це не означало).
fredoverflow

3

Одна відмінність між перевантаженням a * bі викликом multiply(a,b)полягає в тому, що останні можуть легко схопитися за них. Якщо multiplyфункція не перевантажена для різних типів, то ви можете точно дізнатися, що функція буде робити, без необхідності відстежувати типи aта b.

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


Чи не розроблено Linux ядро ​​в чистому C? Навіщо взагалі обговорювати (операторські) перевантаження в цьому контексті?
fredoverflow

Побоювання однакові для будь-якого проекту зі схожим процесом розробки, незалежно від мови. Надмірна перевантаження може ускладнити розуміння впливу змін, якщо все, що вам потрібно буде зробити, - це кілька рядків з файлу патча.
Скотт Уельс

@FredOverflow: Ядро Linux справді знаходиться в GCC C. Він використовує всілякі розширення, які дають його C майже C ++ відчуття у деяких випадках. Я думаю про деякі маніпуляції з фантазійним типом.
Зан Лінкс

2
@Scott: Немає сенсу обговорювати "злість" перевантаження стосовно проектів, запрограмованих на C, оскільки C не має можливості перевантажувати функції.
fredoverflow

3
Лінус Торвальдс, мені здається, має вузьку точку зору. Він іноді критикує речі, які не дуже корисні для програмування ядра Linux, як якщо б це робило їх непридатними для загального використання. Підрив - один із прикладів. Це приємний VCS, але для розробки ядра Linux справді потрібен розподілений VCS, тому Лінус критикував SVN взагалі.
Девід Торнлі

2

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

Особисто я думаю, що є різниця. Коли ви можете змінити поведінку вбудованого синтаксису мови, він стає більш непрозорим для міркувань. Мови, які не дозволяють метапрограмування, синтаксично менш потужні, але концептуально простіші для розуміння.


Перевантажені оператори ніколи не повинні робити "щось дивне". Це добре, якщо, звичайно, робить щось складне. Але перевантажуватися лише тоді, коли воно має одне, очевидне значення.
Sjoerd

2

Я думаю, що перевантаження математичних операторів - це не справжня проблема перевантаження оператора в C ++. Я думаю, що перевантаження операторів, які не повинні покладатися на контекст виразу (тобто типу), є "злом". Наприклад, перевантаження , [ ] ( ) -> ->* new deleteабо навіть одинарне *. Ви маєте певний набір від тих операторів, які ніколи не повинні змінюватися.


+1 Не робіть [] еквівалентом ++.
Майкл К

3
Ви говорите , що ми не повинні бути в змозі перевантажувати оператори , зазначені на всіх ? Або ти просто кажеш, що нам слід перевантажувати їх лише для розумних цілей? Тому що мені б не хотілося бачити контейнери без operator[], функторів без operator(), розумні покажчики без operator->тощо.
fredoverflow

Я кажу, що потенційна проблема перевантаження оператора математичними операціями невелика порівняно з тими операторами. Робити щось розумне чи божевільне з математичними операторами може викликати клопоти, але перераховані я оператори, яких люди зазвичай не вважають операторами, а лише основними мовними елементами, завжди повинні відповідати очікуванню, визначеному мовою. []завжди повинен бути аксесуаром, схожим на масив, і ->завжди повинен означати доступ до члена. Не має значення, чи це насправді масив чи інший контейнер, чи це розумний вказівник чи ні.
Аллон Гуралнек

2

Я прекрасно розумію, що вам не подобається аргумент Джоеля про приховування. Я також ні. Дійсно набагато краще використовувати "+" для таких речей, як вбудовані числові типи або для власних, наприклад, матриця. Я визнаю, що це акуратно та елегантно, щоб можна було помножувати дві матриці на '*' замість '.multiply ()'. І зрештою, ми маємо однаковий вид абстракції в обох випадках.

Тут боляче - читабельність вашого коду. У реальних випадках не в академічному прикладі множення матриць. Особливо, якщо ваша мова дозволяє визначити операторів, які спочатку відсутні в ядрі мови, наприклад =:=. Наразі виникає багато зайвих питань. Про що той проклятий оператор? Я маю на увазі, що є перевагою цієї речі? Що таке асоціативність? У якому порядку a =:= b =:= cреально виконується?

Це вже аргумент проти перевантаження оператора. Ще не переконаний? Перевірка правил пріоритету у вас зайняла не більше 10 секунд? Гаразд, підемо далі.

Якщо ви почнете використовувати мову, яка дозволяє перезавантажувати оператора, наприклад, популярну, назва якої починається з "S", ви швидко дізнаєтесь, що дизайнери бібліотек люблять перекривати операторів. Звичайно, вони добре освічені, вони дотримуються кращих практик (тут немає цинізму), і всі їх API мають ідеальний сенс, коли ми дивимось на них окремо.

Тепер уявіть, що вам доведеться використовувати декілька API, які сильно використовують операторів, що перевантажують разом, в одному коді. Або ще краще - ви повинні прочитати такий спадковий код. Це коли перевантаження оператора дійсно смокче. В основному, якщо в одному місці багато операторів, що перевантажуються, вони незабаром почнуть змішуватися з іншими символами, які не буквено-цифровими, у вашому програмному коді. Вони будуть змішуватися з символами, які не бувають цифрами з альфа-чисел, які насправді не є операторами, а більш елементарними елементами граматики мови, які визначають речі, такі як блоки та області застосування, формують заяви управління потоком або позначають деякі мета-речі. Вам потрібно буде поставити окуляри і посунути очі на 10 см ближче до РК-дисплея, щоб зрозуміти, що це зоровий безлад.


1
Перевантаження існуючих операторів і винахід нових операторів - це не одне і те ж, але +1 від мене.
fredoverflow

1

Взагалі я уникаю використання перевантаження оператора неінтуїтивними способами. Тобто, якщо у мене є числовий клас, перевантаження * допустимо (і заохочується). Однак якщо у мене є працівник класу, що б перевантажувати *? Іншими словами, оператори перевантажують інтуїтивно зрозумілими способами, які полегшують читання та розуміння.

Прийнятні / заохочені:

class Complex
{
public:
    double r;
    double i;

    Complex operator*(const Compex& rhs)
    {
        Complex result;
        result.r = (r * rhs.r) - (i * rhs.i);
        result.i = (r * rhs.i) + (i * rhs.r);
        return result;
    }
};

Не прийнятний:

class Employee
{
public:
    std::string name;
    std::string address;
    std::string phone_number;

    Employee operator* (const Employee& e)
    {
        // what the hell do I do here??
    }
};

1
Примноження працівників? Безумовно, це кривдне порушення, якщо вони роблять це за столом засідань, тобто.
gbjbaanb

1

Окрім сказаного тут, є ще один аргумент проти перевантаження оператора. Дійсно, якщо ви пишете +, це очевидно, що ви маєте на увазі додавання чогось до чогось. Але це не завжди так.

Сам C ++ є чудовим прикладом такого випадку. Як stream << 1слід читати? Потік зміщено вліво на 1? Це зовсім не очевидно, якщо ви прямо не знаєте, що << в C ++ також пише в потік. Однак якби ця операція була реалізована як метод, жоден розумний розробник не писав би o.leftShift(1), це було б щось на зразок o.write(1).

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


1

На відміну від прописаних методів, оператори коротші, але вони також не потребують дужок. Круглі дужки відносно незручні. І ви повинні їх збалансувати. Загалом для будь-якого виклику методу потрібні три символи звичайного шуму порівняно з оператором. Це робить операторів використання дуже, дуже спокусливими.
Чому б ще хтось цього хотів cout << "Hello world":?

Проблема з перевантаженням полягає в тому, що більшість програмістів неймовірно ліниві і більшість програмістів не можуть собі цього дозволити.

Що змушує програмістів C ++ до зловживань перевантаженням оператора - це не його наявність, а відсутність акуратного способу виконання викликів методів. І люди не просто бояться перевантаження оператора тому, що це можливо, а тому, що це зроблено.
Зауважте, що, наприклад, у Ruby та Scala ніхто не боїться перевантаження оператора. Крім того, що використання операторів насправді не коротше методів, ще одна причина полягає в тому, що Ruby обмежує перевантаження оператора до розумного мінімуму, тоді як Scala дозволяє оголосити власних операторів, тим самим уникнувши тривіального уникнення зіткнення.


або в C # для використання + = для прив’язки події до делегата. Я не думаю, що звинувачувати мову в глупості програміста - це конструктивний шлях вперед.
gbjbaanb

0

Причина Оператор Перевантаження страшно, тому , що є велика кількість програмістів , які ніколи б навіть думати , що *зовсім не означає просто «помножити», в той час як метод , як , по foo.multiply(bar)крайней мере відразу ж вказує на той програміст , що хто - то написав спеціальний метод множення . У цей момент вони задумаються, чому і піти розслідувати.

Я працював з "хорошими програмістами", які були на позиціях високого рівня, які створили б методи, звані "Порівняти значення", які брали б два аргументи, і застосовували значення від одного до іншого і повертали булеве значення. Або метод під назвою "LoadTheValues", який би перейшов до бази даних для 3 інших об'єктів, отримав значення, зробив обчислення, змінив thisі збереже його в базі даних.

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.