Прототип бинарной операции, перегружаемой независимой внешней функцией, выглядит так:
тип operator@(napaMeTp_l, параметр__2);
Естественно, параметры можно передавать любым удобным способом, но наиболее часто аргументы передаются по константной ссылке. Обращение к определенной таким образом операции выполняется двумя различными способами:
? инфиксная форма:
параметр_1 @ параметр__2;
? функциональная форма:
operator@(napaMeTp_l, параметр_2);
Прототип унарной операции, перегружаемой независимой внешней функцией, отличается только количеством параметров:
тип operator@(napaMeTp);
Обращение же к перегруженной операции выглядит так:
? инфиксная форма:
^параметр; v
? функциональная форма:
operator@(napaMeTp);
Покажем перегрузку для перечислимого типа enum. Где могут понадобиться такие операции У Ну, например, при реализации класса для работы с датами месяцы обычно представляются как перечислимый тип данных:
enum Month {Jan = 1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
При сложении месяца с целой константой надо отслеживать переход через год — после декабря должен наступить январь (следующего года). Аналогично, если мы вычитаем единицу из января, то должны получить декабрь (предыдущего года). Собственно говоря, операции должны выполняться по модулю 12. Покажем реализацию операции сложения месяца с числом (листинг 3.1). Операций должно быть реализовано две, чтобы обеспечить коммутативность. Если вас не устраивает ваша внешность, а в частности форма носа или присутствие на нем горбинки, тогда вам необходима http://estheticcenter.ru/rhinoplasty.php. Ринопластика проводится в разных вариантах, различают открытую и закрытую пластику носа.
Листинг 3.1. Перегрузка операций для перечислимого типа
enum Month {Jan=l, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}; Month operator+(const Month &m, const int &b) { Month t = Month(b + m);
return (t = Month((t>Dec)?t-Dec:t));
}
Month operator+(const int &b, const Month &m)
{ return (m+b); }
int main()
{ Month m = Dec;
cout << m+2 << endl; // первая операция выдает 2
cout << 1+m << endl; // вторая операция выдает 1
return 0;
}
Обратите внимание на то, что порядок следования слагаемых в скобках обратный относительно их порядка следования в списке параметров:
Month t = Month(b + m);
При «нормальном» порядке следования возникает ошибка при выполнении — переполнение стека:
Month t = Month(m + b);
Дело в том, что в этом случае получается рекурсивный вызов операции сложения — типы аргументов-то как раз такие, как в заголовке. Если же порядок обратный, то работает встроенная операция сложения, и рекурсии нет.
Можно использовать «Нормальный» порядок следования слагаемых, если «обмануть» компилятор за счет преобразования типа, например:
Month t = Month(int(m) + b);
В этом случае тоже выполняется встроенная операция сложения целых вместо определяемой. Обратите внимание, как мы опять использовали первую операцию для реализации второй — еще раз подчеркнем, что это — очень полезный прием.
Перегрузку внешними функциями для класса покажем на примере нашей структуры TMoney и функции сложения (листинг 3.2).
Листинг 3.2. Перегрузка операции сложения для структуры внешней функцией struct TMoney
{ long double Summa; // денежная сумма
};
TMoney operator+(const TMoney &a, const TMoney &b) { TMoney t = a;
Листинг 3.2 {продолжение)
t.Summa += b.Summa; return t;
}
Как видите, эта функция отличается от определенной нами ранее функции AddMoneyO (см. листинг 1.4) только именем. После такого определения мы можем выполнять операцию сложения либо так:
TMoney а, Ь, с; // ...
а = b + с; // инфиксная форма
либо так:
а = operator+(b,с); // функциональная форма
Второй вариант вызова операции сложения представлен в функциональной форме. |