Перевантаження операторів, 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. Правильне застосування цієї потужної можливості дозволити зробити Ваш код більш Новомосковскбельним і полегшить його розуміння іншими розробниками і подальше його супровід.

Весь код наведених прикладів ви можете завантажити за цим посиланням.