# Предефиниране на оператори. Приятелски класове и функции. Mutable член-данни. ## Oператори ### Видове оператори. в C++ има два вида оператори: - Унарни (на един аргумент) - Бинарни (на два аргумента) ### Операторите се характеризират с: - Приоритет - Асоциативност - Позиция на оператора спярмо аргумента - *префиксен*, *инфиксен* и *суфиксен* ### Списъка на операторите в C++: | Оператор | Асоциативност | |------------------------------------------------|---------------------------------| | () [] -> . ++ - - | лявоасоциативен | | + - ! ~ ++ - - (type)* & sizeof | дясноасоциативен | | * / % | лявоасоциативен | | + - | лявоасоциативен| | << >> | лявоасоциативен| | < <= > >= | лявоасоциативен| | == != | лявоасоциативен| | & | лявоасоциативен | | ^ | лявоасоциативен | | \| | лявоасоциативен| | && | лявоасоциативен| | \|\| | лявоасоциативен| | ?: | дясноасоциативен | | = += -= *= /= %= >>= <<= &= ^= | дясноасоциативен | ### Предефиниране на оператор (пример) ```c++ Complex& Complex::operator+=(const Complex& other) { real += other.real; im += other.im; return *this; } ``` Вече може да правим следното: ```c++ int main() { Complex c(1,3); //1 + 3i; Complex c2(10,20) // 10 + 2i; c += c2 // now c is 11 + 5i } ``` При предефинирането на оператор **не могат** да се променят *приоритетът*, *асоциативността*, броят и позицията на *аргументите* му. ## Приятелски класове и приятелски функции Декларират се с на запазената дума **friend** пред прототипа на функцията. Даденият friend-клас/фунцкия има достъп до всички компоненти на класа. Т.е. всички членове на класа са public за friend-класовете/функциите приятели. ### Приятелски функции (пример) ```c++ class Complex { private: double real; double im; public: friend double getModulos(const Complex& other); . . . } ``` ```c++ double getModulos(const Complex& other) { return sqrt((other.real – other.real) * (other.real – other.real) + (other.im – other.im ) * (other.im – other.im)); } ``` ### Mutable (пример) Спецификатора mutable е приложен само в С++. Той позволява на член на обект да предефинира константността. Така mutable член на const обект не е const и може да бъде изменян. ```c++ struct Test { private: mutable int n; public: void f() const { n++; } }; int main() { const Test t; t.f(); } ``` ## Задачи **Задача 1:** Реализирайте клас **Nvector**, който ще се използва за работа с математически вектор. Предефинирайте оператори със следната функционалност: - Събиране на вектори. - Изваждане на вектори. - Умножение на вектор със скалар. - Проверка дали два вектора са успоредни. - Проверка дали два вектора са перпендикулярни. - Взимане на дължина на вектор. - Достъп до произволен елемент на вектор. - Вход и изход от потоци. ```c++ int main() { Nvector v(4); cin >> v; Nvector v2(4); cin >> v; Nvector result = v + v2; cout << result << endl; } ``` Релизирайте клас двумерната декартова координатна система, която приема 2 вектора, които са нейният базис. Реализрайте следните функции: - Връща вектор в базиса по подадени 2 координата. - По подаден вектор връща координатите му в базиса. ```c++ int main() { Nvector v(4); v[0] = 2; v[1] = 1; Nvector v2(4); v2[0] = 3; v2[1] = 1; twoDimCoordSystem s(v1, v2); cout << s1.getVectorByCoordinates(7, 4); // [26, 11] cout << s1.getCoordinatesByVector(7, 4); // [5, -1] cout << result << endl; } ``` **Задача 2:** Реализирайте клас **ComplexNumber**, който ще се използва за работа с комплексни числа. Предефинирайте оператори със следната функционалност: - Събиране на комплексни числа. - Изваждане на комплексни числа. - Умножение на комплексни числа. - Деление на комплексни числа - Вход и изход от потоци. ```c++ int main() { ComplexNumber c; cin >> c; ComplexNumber c2; cin >> c2; ComplexNumber result = c2 / c; cout << result << endl; } ``` **Задача 3:** Релизирайте клас - множество(**без повторение**) от думи от малки/главни латински букви и цифри. В колекцията ви търсенето трябва да е с логаритмична сложност. Предефинирайте оператори: - += и +. Събиране на две колекции. - -= и -. От думите на лявата колекция, се премахват тези, които участват в дясната. - [], който приема дума и връща дали стрингът е в колекцията (очакваме логаритмично време). - *= за добавяне на дума - /= за премахване на дума. - << (поток за изход. Отпечатва всички думи в сортиран вид). - \>\> (поток за вход. Приема думa, която да се добави в речника). **Важно!** Копирането на стрингове е бавна операция! Помислете как да организирате данните, за да имате логаритмично търсене на дума и при добавяне на нова дума да правите **минимален брой копирания** на стрингове! ```c++ int main() { StringPool dict; ((dict *= "Ivan") *= "Petur") *= "Alex"; std::cout << dict << std::endl; // {Alex, Ivan, Petur} std::cout << dict["Alex"] << " " << dict["abc"] << std::endl; // 1 0 StringPool dict2; ((dict2 *= "Zebra") *= "Alex"); StringPool result = dict + dict2; std::cout << result << std::endl; // {Alex, Ivan, Petur, Zebra} StringPool result2 = dict - dict2; std::cout << result2 << std::endl; // {Ivan, Petur} "NewWOrd" >> result2; result2 /= "NonExistingWord"; std::cout << result2 << std::endl; //{Ivan, NewWOrd, Petur} "Job" >> result2; std::cout << result2 << std::endl; //{Ivan, Job, NewWOrd, Petur} } ```