Розробка власного класу STRING
Курсовой проект - Компьютеры, программирование
Другие курсовые по предмету Компьютеры, программирование
одженню між операцією присвоювання й конструктором копіювання і еквівалентно розходженню між функціями _draw () і draw (). Відзначимо, що функція copy () не є віртуальною. Їй і не треба бути такою, оскільки віртуальна викликаюча її функція clone (). Очевидно, що прості операції копіювання можна також визначати як функції-підстановки.
1.15 Перевантаження операцій
Звичайно в програмах використовуються обєкти, що є конкретним поданням абстрактних понять. Наприклад, у С++ тип даних int разом з операціями +, - , *, / і т.д. реалізує (хоча й обмежено) математичне поняття цілого. Звичайно з поняттям звязується набір дій, які реалізуються в мові у вигляді основних операцій над обєктами, що задають у стислому, зручному й звичному виді. На жаль, у мовах програмування безпосередньо представляється тільки мале число понять. Так, поняття комплексних чисел, алгебри матриць, логічних сигналів і рядків у С++ не мають безпосереднього вираження. Можливість задати подання складних обєктів разом з набором операцій, котрі виконуються над такими обєктами, реалізують у С++ класи. Дозволяючи програмістові визначати операції над обєктами класів, ми одержуємо більше зручну й традиційну систему позначень для роботи із цими обєктами в порівнянні з тієї, у якій всі операції задаються як звичайні функції. Приведемо приклад:
class complex {
double re, im;
public:
complex (double r, double i) { re=r; im=i; }
friend complex operator+ (complex, complex);
friend complex operator* (complex, complex);
};
Тут наведена проста реалізація поняття комплексного числа, коли воно представлено парою чисел із плаваючою крапкою подвійної точності, з якими можна оперувати тільки за допомогою операцій + і *. Інтерпретацію цих операцій задає програміст у визначеннях функцій з іменами operator+ і operator*. Так, якщо b і c мають тип complex, те b+c означає (по визначенню) operator+ (b,c). Тепер можна наблизитися до звичного запису комплексних виражень:
void f ()
{
complex a = complex (1,3.1);
complex b = complex (1.2,2);
complex c = b;
a = b+c;
b = b+c*a;
c = a*b+complex (1,2);
}
Зберігаються звичайні пріоритети операцій, тому другий вираз виконується як b=b+ (c*a), а не як b= (b+c) *a.
1.15.1 Операторні функції
Можна описати функції, що визначають інтерпретацію наступних операцій:
+ - * /% ^ & | ~!
= += - = *= /=%= ^= &=
|= = &&
|| ++ - і - >*, - > [] () new delete
Останні пять операцій означають: непряме звертання, індексацію, виклик функції, розміщення у вільній памяті й звільнення. Не можна змінити пріоритети цих операцій, так само як і синтаксичні правила для виразів. Так, не можна визначити унарну операцію%, також як і бінарну операцію!. Не можна ввести нові лексеми для позначення операцій, але якщо набір операцій вас не влаштовує, можна скористатися звичним позначенням виклику функції. Тому використайте pow (), а не **. Ці обмеження можна ввжати драконівськими, але більш вільні правила легко приводять до неоднозначності. Припустимо, ми визначимо операцію ** як піднесення до степеня, що на перший погляд здається очевидним і простим завданням. Але якщо як варто подумати, то виникають питання: чи належні операції ** виконуватися ліворуч праворуч або праворуч ліворуч? Як інтерпретувати вираження a**p як a* (*p) або як (a) ** (p)?
Імям операторної функції є службове слово operator, за яким іде сама операція, наприклад, operator<<. Операторна функція описується й викликається як звичайна функція. Використання символу операції є просто короткою формою запису виклику операторної функції:
void f (complex a, complex b)
{
complex c = a + b; // коротка форма
complex d = operator+ (a,b); // явний виклик
}
З урахуванням наведеного опису типу complex ініціалізатори в цьому прикладі є еквівалентними.
1.15.2 Бінарні й унарні операції
Бінарну операцію можна визначити як функція-член з одним параметром, або як глобальну функцію із двома параметрами. Виходить, для будь-якої бінарної операції @ вираження aa @ bb інтерпретується або як aa. operator (bb), або як operator@ (aa,bb). Якщо визначені обидві функції, то вибір інтерпретації відбувається за правилами зіставлення параметрів. Префіксна або постфіксна унарна операція може визначатися як функція-член без параметрів, або як глобальна функція з одним параметром. Для будь-якої префиксної унарної операції @ вираження @aa інтерпретується або як aa. operator@ (), або як operator@ (aa). Якщо визначені обидві функції, то вибір інтерпретації відбувається за правилами зіставлення параметрів. Для будь-якої постфіксної унарної операції @ вираз @aa інтерпретується або як aa. operator@ (int), або як operator@ (aa, int). Якщо визначені обидві функції, то вибір інтерпретації відбувається за правилами зіставлення параметрів. Операцію можна визначити тільки відповідно до синтаксичних правил, наявними для неї в граматиці С++. Зокрема, не можна визначити% як унарну операцію, а + як тернарну. Проілюструємо сказане прикладами:
class X {
// члени (неявно використається покажчик this):
X* operator& (); // префіксна унарная операція &
// (узяття адреси)
X operator& (X); // бінарна операція &
X operator++ (int); // постфіксний інкремент
X operator& (X,X); // помилка: & не може бути тернарною
X operator/ (); // помилка: / не може бути унарною
};
// глобальні функції (звичайно друзі)
X operator- (X); // префіксний унарный мінус
X operator- (X,X); // бінарний мінус
X operator-і (X&, int); // постфіксни?/p>