Във всяка наука има стандартни обозначения, които улесняват разбирането на идеите. Например в математиката става дума за умножение, разделяне, добавяне и друга символична нотация. Изразът (x + y * z) е много по-лесен за разбиране от "умножаване на y, z и добавяне към x". Представете си, че до XVI век математиката не е имала символична нотация, всички изрази са написани устно, сякаш е художествен текст с описание. И обичайните признаци на операции за нас се появиха по-късно. Трудно е да се надценява смисъла на кратък запис на характер. Въз основа на тези съображения езиците за програмиране бяха добавени към претоварването на операторите. Помислете за примера.
Пример за претоварване на оператор
//представете сложно число под формата на двойка числа сс плаваща запетая.
класов комплекс {{12} двоен ре, im;
публичен:
комплекс (двойно r, двойно i): re (r), im (i) {} //конструктор
сложен оператор + (комплекс); //претоварващ комплект
сложен оператор * (комплекс); претоварването на умножението
;
невалиден главен () {
комплекс a {1 2}, b {3}}, c {0}};
c = a + b;
с = а.оператор + (б); ////операторната функция може да се нарече всяка функция, този запис е еквивалентен на a + b
c = a * b + комплекс (1 3); //Изпълняваме обичайните правила на приоритета на операциите по прибавяне и умножение
}
По подобен начин можете да направите, например, претоварване на I /O оператори в C ++ и да ги адаптирате за извеждане на такива сложни структури като матрици.
На разположение на операторите за претоварване
Пълен списък на всички оператори, за които може да се използва механизмът за претоварване:
+*/ 39]110нови% | ^ | & amp; | ||||
| | ~ | ! | = | . | & gt; | + = |
- = | * = | /= | ^ = | и | | 62] | |
= | = | == 84] | ! = | |||
> = | &; | || | ++ | - * | , | |
- & gt; | изтриване | изтриване [] |
Както може да се види от таблицата, претоварването е допустимо за повечето езикови оператори. Не е необходимо претоварване на оператора. Това се прави единствено за удобство. Следователно, претоварването на операторите в Java например отсъства. А сега за такъв важен момент.
Оператори, чието претоварване е забранено
- Разрешение за видимост - «::»;
- Изборът на член е ".";
- Избор на член чрез указател към член - ". *";
- Троен условен оператор - «?:»;
- размер на оператора;
- Операторът на типа.
Десният операнд на данните на операторите е името, а не стойността. Следователно разрешението за тяхното претоварване би могло да доведе до писането на много двусмислени дизайни и значително ще усложни живота на програмистите. Въпреки че има много езици за програмиране, които позволяват претоварването на всички оператори - например претоварването на операторите на Python.
& lt; script type = "text /javascript" & gt;
може blockSettings2 = {blockId: "R-A-70350-2", renderTo: "yandex_rtb_R-A-70350-2", async:! 0};
if (document.cookie.indexOf ("abmatch =") & gt; = 0) {
blockSettings2 = {blockId: "RA-70350-2", renderTo: "yandex_rtb_R-A-70350- 2 ", statId: 70350async:! 0};
}
Функция (a, b, c, d, e) {a [c] = a [c] || [], a [c] .push (функция () {Ya .Context.AdvManager.render (blockSettings2)}), e = b.getElementsByTagName ("script") , d = b.createElement ("script"), d.type = "text /javascript", d.src = "//an.yandex.ru/system/context.js", d.async =! 0e.parentNode.insertBefore (d, e)} (това, този.документ, "yandexContextAsyncCallbacks");
Ограничения
Ограничение на претоварването на оператора:
- Не можете да промените двоичния оператор на унарните и обратно, тъй като не можете да добавите третия операнд.
- Не можете да създавате нови оператори, различни от тези, които са. Това ограничениенасърчава премахването на много неясноти. Ако има нужда от нов оператор, можете да използвате функция, която ще изпълни желаното действие за тези цели.
- Операторната функция може да бъде член на клас или да има поне един тип аргумент. Изключение са новите и изтриване на оператори. Това правило забранява промяна на значението на изразите, ако те не съдържат потребителски типове обекти. По-специално, не можете да създадете операторска функция, която да работи само с указатели или да принуди оператора на добавянето да работи като умножение. Изключения са операторите "=", "& amp;" и "," за класовите обекти.
- Операторската функция с първия термин, принадлежаща на един от вградените типове данни на езика на C ++, не може да бъде член на класа.
- Името на всяка операторска функция започва с ключовата дума оператор, последвана от символично обозначение на самия оператор.
- Вградените оператори се дефинират по такъв начин, че между тях има връзка. Например, следните оператори са еквивалентни един на друг: ++ x; х + = 1; x = x + 1. След предефиниране връзката между тях няма да се запази. За да запазят своята работа заедно по подобен начин с новите типове програмисти ще трябва да се грижат за себе си.
- Компилаторът не може да мисли. Изрази z + 5 и 5 + z (където z - комплексно число) ще бъдат разглеждани от компилатора по различни начини. Първият е "комплекс + номер", а вторият е "брой + комплекс". Следователно за всеки израз трябва да определите собствено изявление за добавяне.
- При търсене на дефиниция на оператор, компилаторът не дава предпочитание на никакви функционални членове на класа, нито на помощни функции,които са определени извън клас. За компилатора те са еднакви.
Интерпретации на двоични и единни оператори.
Двоичен оператор се дефинира като функция на член с една променлива или като функция с две променливи. За всеки бинарен оператор @ изразът a @ b @ е валиден конструкт:
& lt; script type = "text /javascript" & gt;
може да blockSettings3 = {blockId: "R-A-70350-3", renderTo: "yandex_rtb_R-A-70350-3", async:! 0};
blockSettings3 = {blockId: "RA-70350-3", renderTo: "yandex_rtb_R-A-70350-" 3 ", statId: 70350async: 0};
}
Функция (a, b, c, d, e) {a [c] = a [c] || [], a [c] .push (функция () {Ya .Context.AdvManager.render (blockSettings3)}), e = b.getElementsByTagName ("скрипт") , d = b.createElement ("скрипт"), d.type = "text /javascript", d.src = "//an.yandex.ru/system/context.js", d.async =! 0e.parentNode.insertBefore (d, e)} (това, този.документ, "yandexContextAsyncCallbacks");
а.оператор @ (б) или оператор @ (а, б).
Да вземем за пример един клас от комплексни числа за дефиниране на операции като членове на клас и помощни.
класов комплекс {{174} двойно ре, im;
публичен:
комплексен; оператор + = (комплекс z);
комплекс & на; оператор * = (комплекс z);
};
//спомагателни функции
сложен оператор + (комплекс z1 комплекс z2);
сложен оператор + (комплекс z, double a);
Кой от операторите ще бъде избран и дали изобщо ще бъде избран, се определя от вътрешните механизми на езика, които ще бъдат разгледани по-долу. Обикновено това се случва в съответствие с видовете.
Избор, за да се опише функция като член на клас или извън нея - правилно, общо взето, вкус. В примера по-горе, принципът на подбор е следният: ако операцията промени левия операнд (например a + = b), напишете го вътре в класа и използвайте прехвърлянето на променливата на адреса за неговата пряка промяна; ако операцията не е нищомодифицира и просто връща нова стойност (например a + b) - извън дефиницията на класа.
Определението за претоварване на унарните оператори в C ++ възниква по същия начин, с тази разлика, че те са разделени на два вида:
- префикс оператор, разположен към операнда, - @, например, i ++. o Дефинирано като a.operator @ () или оператор @ (aa);
- постфикс оператор, разположен след операнда, - b @, например, i ++. o Определени като b.operator @ (int) или оператор @ (b, int)
По същия начин, както при бинарните оператори, в случая, когато изявлението на оператора е както в класа, така и извън него, изборът ще бъде направен от механизмите на C ++.
Правила за избор на оператор
Нека двоичният оператор @ се прилага към обекти x от клас X и y от клас Y. Правилата за разделителната способност x @ y ще бъдат както следва:
- ако X е клас, потърсете в него дефиницията на оператора @ като термин X или базовия клас X;
- да се види контекстът, в който е разположен изразът x @ y;
- ако X принадлежи към пространството от имена N, потърсете оператора N;
- Ако Y принадлежи към пространството на имената M, потърсете изявлението на оператора M.
Ако няколко оператора на оператор @ са намерени в 1-4, изборът ще бъде направен съгласно правилата за разрешение на претоварените функции.
Търсенето на единични оператори се извършва по същия начин.
Уточнете дефиницията на класовия комплекс
Сега ще конструираме клас от комплексни числа по по-детайлен начинда покаже редица предварително обявени правила.
клас комплекс {
double re, im;
публични:
комплексни; operator + = (complex z) {//работи с изрази на формата z1 + = z2
re + = z.re;
im + = z.im;
връщане * това;
}
комплексен; оператор + = (double a) {//работи с изрази от вида z1 + = 5;
re + = a;
връщане * това;
}
complex (): re , im
{} //конструктор за инициализация по подразбиране. По този начин всички декларирани цели числа ще имат начални стойности (0 0)
комплекс (двойни r): re (r), im
{} //конструкторът прави възможно изразът на формата комплекс z = 11; еквивалент на запис z = комплекс
;
комплекс (двойно r, двойно i): re (r), im (i) {} //конструктор
};
сложен оператор + (сложен z1 комплекс z2) {//работи с изрази на вида z1 + z2
комплекс res = z1;
връщане res + = z2; //използваме оператор, дефиниран като член функция
}
сложен оператор + (комплекс z, double a) {//обработва изрази на формата z + 2
комплекс res = z;
връщане res + = a;
}
сложен оператор + (double a, complex z) {//обработва изразите на формата 7 + z
комплекс res = z;
връщане res + = a;
}
//
Както може да се види от кода, претоварването на операторите има доста сложен механизъм, който може значително да нарасне. Въпреки това, такъв подробен подход ви позволява да претоварвате дори при много сложни структури от данни. Например, претоварване на операторите на C ++ в шаблонен клас. Такова създаване на функции за всички и всичко може да бъде досадно и да доведе до грешки. Например, ако добавите трети тип разгледани функции, тогава ще трябва да обмислите операциите поради комбинация от три типа. Ще трябва да напишем 3 функции с един аргумент, 9 - с две и 27 - с три. Ето защо, в някои случаи, изпълнението на всички тези функции и значително намаляване на тяхколичествата могат да бъдат постигнати чрез конвертиране на типове.
;
комплекс (двойно r, двойно i): re (r), im (i) {} //конструктор
};
сложен оператор + (сложен z1 комплекс z2) {//работи с изрази на вида z1 + z2
комплекс res = z1;
връщане res + = z2; //използваме оператор, дефиниран като член функция
}
сложен оператор + (комплекс z, double a) {//обработва изрази на формата z + 2
комплекс res = z;
връщане res + = a;
}
сложен оператор + (double a, complex z) {//обработва изразите на формата 7 + z
комплекс res = z;
връщане res + = a;
}
//