Перевантаження операторів в c

Перевантаження операторів в c

У багатьох мовах програмування використовуються оператори: як мінімум, привласнення (=. = Або схожі) і арифметичні оператори (+. -. * І /). У більшості мов зі статичної типізацією ці оператори прив'язані до типів. Наприклад, в Java складання з оператором + можливо лише для цілих чисел, чисел з плаваючою комою і рядків. Якщо ми визначимо свої класи для математичних об'єктів, наприклад, для матриць, ми можемо реалізувати метод їх складання, але викликати його можна лише чимось на зразок цього: a = b.add (c).

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

Коли варто перевантажувати оператори?

Запам'ятайте головне: перевантажуйте оператори тоді і тільки тоді, коли це має сенс. Тобто якщо сенс перевантаження очевидний і не несе в собі прихованих сюрпризів. Перевантажені оператори повинні діяти так само, як і їхні базові версії. Природно, допустимі винятки, але лише в тих випадках, коли вони супроводжуються зрозумілими поясненнями. Наочним прикладом є оператори <<и>> Стандартної бібліотеки iostream. які явно ведуть себе не як звичайні оператори бітового зсуву.

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

Прикладом поганий перевантаження оператора складання буде складання двох об'єктів типу "гравець" в грі. Що мав на увазі автор класу? Яким буде результат? Ми не знаємо, що робить операція, і тому користуватися цим оператором небезпечно.

Як перевантажувати оператори?

Перевантаження операторів схожа на перевантаження функцій з особливими іменами. Насправді, коли компілятор бачить вираз, в якому присутній оператор і призначений для користувача тип, він замінює цей вислів викликом відповідної функції перевантаженого оператора. Велика частина їх назв починається з ключового слова operator. за яким іде позначення відповідного оператора. Коли позначення не складається з особливих символів, наприклад, в разі оператора приведення типу або управління пам'яттю (new. Delete і т.д.), слово operator і позначення оператора повинні розділятися пропуском (operator new), в інших випадках пропуском можна знехтувати (operator + ).

Більшу частину операторів можна перевантажити як методами класу, так і простими функціями, але є кілька винятків. Коли перевантажений оператор є методом класу, тип першого операнда повинен бути цим класом (завжди * this), а другий повинен бути оголошений в списку параметрів. Крім того, оператори-методи не статичні, за винятком операторів управління пам'яттю.

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

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

Реалізуйте унарні оператори і бінарні оператори типу "X =" у вигляді методів класу, а інші бінарні оператори - у вигляді вільних функцій.

Які оператори можна перевантажувати?

Ми можемо перевантажити майже будь-який оператор C ++, з огляду на такі винятки і обмеження:

  • Не можна визначити новий оператор, наприклад, operator **.
  • Наступні оператори перевантажувати не можна:
    1. . (Тернарний оператор);
    2. . (Доступ до вкладених імен);
    3. . (Доступ до полів);
    4. .* (Доступ до полів за вказівником);
    5. sizeof. typeid і оператори каста.
  • Наступні оператори можна перевантажити тільки в якості методів:
    1. = (Присвоювання);
    2. -> (Доступ до полів за вказівником);
    3. () (виклик функції);
    4. [] (Доступ за індексом);
    5. -> * (Доступ до покажчика-на-поле за вказівником);
    6. оператори конверсії та управління пам'яттю.
  • Кількість операндів, порядок виконання і асоціативність операторів визначається стандартною версією.
  • Як мінімум один операнд повинен бути користувальницького типу. Typedef не рахується.

Переклад статті «Operator Overloading: The Basics»

Схожі статті