Перевантаження операторів, delphi і
Прочитавши назву, Ви не помилилися - у восьмій версії Delphi (Delphi.NET) тепер дійсно стала можлива перевантаження операторів. З виходом Delphi.NET в мові Object Pascal з'явилося багато мовних змін, найзначніших починаючи з версії 1.0. Для того щоб розглянути їх усі, знадобилася б окрема книга, тому в даній статті ми розглянемо тільки одне, на мій погляд, найцікавіше розширення мови - перевантаження операторів.
Можливість автоматичного заміщення операторів в початковому тексті програми для користувача функціями давно знайома програмістам пишуть на мовах C ++ і C #. Тепер ця чудова можливість доступна і Delphi-програмістам.
Загальні правила
У Delphi.NET, на відміну від С-подібних мов, таких як C ++ і C #, для того, щоб перевантажити оператор, потрібно реалізувати функцію з певною сигнатурою (а не з символом оператора!) - тобто реалізувати функцію з певним ім'ям, числом і типами параметрів. У Таблиці 1 наведено список операторів, для яких допускається перевизначення, і сигнатури функцій, які для цього потрібно реалізувати.
Таблиця 1.Спісок операторів, для яких в Delphi.NET можливе перевантаження
Цікаво відзначити, що такі часто використовувані функції, як Round і Trunc є в Delphi.NET операторами, тобто за формою виклику нічим не відрізняються від функцій, але можуть бути перевантажені.
Після цього в тексті програми можливе використання наступного коду:
Далі ми більш детально розглянемо перевантаження для різних груп операторів
Перевантаження унарних операторів
Унарні оператори отримують на вході один аргумент, а в якості результату повертають екземпляр певного типу. У загальному випадку тип вхідного параметра і тип результату оператора можуть збігатися.
Розглянемо приклад подібного унарна оператора: припустимо у нас є тип: розширений список рядків у вигляді класу TMyStringList успадкованих від класу TStringList бібліотеки VCL:
Для даного класу ми хочемо визначити оператор арифметичного заперечення '-'. Нехай цей оператор буде виробляти переупорядочивание елементів списку в зворотному порядку: тобто перший елемент стає останнім, другий - передостаннім і т.д. Як результат даний оператор повинен повертати новий результуючий список.
Для реалізації такого оператора нам необхідно оголосити наступний метод класу:
Для демонстрації цього прикладу створимо невелику консольний додаток. Повний вихідний код буде виглядати наступним чином:
Перевантаження бінарних операторів
Бінарний оператор являє собою функцію, яка отримує два параметри, а як результат повертає екземпляр певного типу. Як і для унарних операторів, типи вхідних параметра і тип результату роботи оператора також можуть збігатися.
Розглянемо приклад подібного бінарного оператора: для нашого класу TMyStringList визначимо оператор арифметичного додавання з рядком "+", який буде додавати цей рядок в кінець списку.
Для реалізації такого оператора нам необхідно оголосити наступної метод:
У наведеному вище прикладі, для наочності, перетворення здійснюється до примітивних типів (String, integer, Boolean), в реальних додатках приведення можливо до довільного класу. Наприклад, приведення екземпляра класу TAccount (банківський рахунок) до типу TConractor (контрагент) може повертати власника рахунку, а приведення до типу Real буде повертати залишок на рахунку.
Перевантаження операторів приведення типу є дуже потужним механізмом, і використовувати його треба з обережністю, ретельно спланувавши можливі перетворення - особливо це стосується неявного перетворення. В іншому випадку це може привести до важко що виявляється помилок.
розширені можливості
На закінчення своєї розповіді я хотів би розповісти Вам про цікаві можливості, які надають перевантаження операторів.
Створення копіює конструктора
Ідея полягає у визначенні оператора явного перетворення екземпляра класу до такого ж класу.
Перевантаження оператора присвоювання
Якщо Ви уважно дивилися список операторів, для яких можливо перевантаження, то звернули увагу, що там немає оператора присвоювання. Дійсно, перевантаження оператора присвоювання ": =" заборонена.
Однак в одному випадку цього можна домогтися: при використання класів які завжди мають тільки один екземпляр. Прикладом такого примірника є змінна Application типу TApplication бібліотеки VCL. Може існувати тільки один екземпляр класу TApplication, і він є глобальної змінної; його створення і знищення реалізовано в бібліотеці VCL і відбувається автоматично.
Отже, для подібних об'єктів можлива неявна перевантаження оператора присвоювання.
Для цього екземпляр класу оголошується статичним полем того ж самого класу, і у нього перекривається оператор приведення до потрібного типу. Створення такого поля можливо в конструкторі класу. Після цього стає можливим перевизначення привласнення примірника довільного класу даному поточному примірнику.
Проілюструємо вищесказане прикладом: в нашому додатку реалізований журнал обліку операцій у вигляді текстового файлу (log-файл). Даний log-файл представлений у вигляді класу Logger. завжди існує тільки один екземпляр даного класу, і всі модулі програми звертаються до нього, щоб записати чергове повідомлення.
Тепер стає можливим операція присвоєння рядки (string) змінної Logger.
висновок
Ми розглянули приклади перевантаження операцій в Delphi.NET. Правильне застосування цієї потужної можливості дозволити зробити Ваш код більш Новомосковскбельним і полегшить його розуміння іншими розробниками і подальше його супровід.
Весь код наведених прикладів ви можете завантажити за цим посиланням.