- •5. Перегрузка, копирование и преобразование
- •5.1. Перегрузка операторов
- •5.1.1. Определение дополнительных функций-операторов
- •5.1.2. Общие принципы перегрузки операторов
- •5.1.3. Перегрузка оператора присваивания
- •5.2. Применение конструкторов копирования и преобразования
- •5.2.1. Конструкторы копирования
- •5.2.2. Конструкторы преобразования
- •5.2.3. Инициализация массивов
5.1.1. Определение дополнительных функций-операторов
Подобно другим функциям языка C++, функции-операторы могут быть перегружены. При этом есть несколько способов вызова операторов. Например, с помощью оператора "+" можно сложить объект класса CCurrency с константой типа int или long. (В определенной выше функции предполагается, что оба операнда являются объектами класса CCurrency.) Для этого в класс CCurrency нужно добавить следующую функцию.
CCurrency operator+ (long Dol)
{
return CCurtency (Dollars + Dol, Cents);
}
Включение этой функции позволит использовать оператор «+» следующим образом.
CCurrency Advertising (235, 42);
// ...
Advertising+ = 100;
Компилятор будет интерпретировать выражение Advertising + 100 как
Advertising.operator+ (100)
и, следовательно, вызывать вновь определенную версию функции operator+. Тем не менее, целочисленную константу нельзя поставить первой, так как компилятор будет интерпретировать выражение 100 + Advertising как
100.operator+ (Advertising) // бессмысленно!
Чтобы обойти это ограничение, можно написать функцию-оператор, которая не является членом класса, но первый параметр которой имеет тип long.
// определяется глобально:
CCurrency operator+ (long Dol, const CCurrency SCurr)
{
return CCurrency (Dol + Curr.Dollars, Curr.Cents);
}
Но при использовании этой функции также могут возникнуть проблемы. Так как она не является функцией-членом класса CCurrency, то не имеет доступа к закрытым переменным этого класса (а именно, к Dollars и Cents). Для получения такого доступа функцию нужно сделать дружественной классу CCurrency, объявив ее внутри определения CCurrency с использованием спецификатора friend.
class CCurrency
{
// другие объявления ...
friend CCurrency operator+ (long Dol, const CCurrency &Curr);
// другие объявления ...
};
Даже если дружественная функция не является функцией-членом класса, она имеет доступ как к закрытым, так и к защищенным членам класса, который объявляет ее дружественной.
Когда такая функция-оператор определена, операцию сложения можно применить следующим образом.
CCurrency Advertising (235, 42);
// ...
Advertising = 100 + Advertising;
Теперь компилятор проинтерпретирует выражение 100 + Advertising как
operator+ (100, Advertising)
и, следовательно, вызовет дружественную версию функции-оператора.
Заметим: можно сделать дружественными две первые версии функции operator+, не определяя их как функции-члены класса (хотя особенного преимущества это не дает).
friend CCurrency operator+ (const CCurrency &Curr1,
const CCurrency &Curr2);
friend CCurrency operator+ (const CCurrency &Curr, long Dol);
Функция, перегружающая оператор и не являющаяся методом класса, должна иметь хотя бы один параметр – объект класса. Следовательно, функцию-оператор нельзя использовать для изменения стандартного смысла операторов в выражении, содержащем только данные встроенных типов.
Дружественные классы
В определении класса также можно объявить дружественным другой класс, например:
class A
{
// ...
friend class FriendOfA;
// ...
};
Благодаря такому объявлению любая функция-член класса FriendOfA имеет доступ к закрытым и защищенным членам класса А.
Ниже приведено полное описание класса CCurrency вместе с функцией, не являющейся его членом.
#include <iostream.h>
class CCurrency
{
private:
long Dollars;
int Cents;
public:
CCurrency ()
{
Dollars = Cents = 0;
}
CCurrency (long Del, int Cen)
{
SetAmount (Dolf Cen);
}
void GetAmount (long *PDol, int *PCen}
{
*PDol = Dollars;
*PCen = Cents;
}
void PrintAmount { )
{
cout.fill 'O');
cout.width (1) ;
cout << '$' << Dollars << '.';
cout.width (2) ;
cout << Cents << '\n';
}
void SetAmount (long Dol, int Cen)
{
// проверка суммы центов, которая превышает 100:
Dollars = Dol +• Cen / 100;
Cents = Cen % 100;
}
CCurrency operator+ (const CCurrency &Curr)
{
return CCurrency (Dollars + Curr.Dollars, Cents + Curr.Cents);
}
CCurrency operators- (long Dol)
{
return CCurrency (Dollars + Dol, Cents);
}
friend CCurrency operator+ (long Dol, const CCurrency &Curr);
};
CCurrency operator+ (long Dol, const CCurrency &Curr)
{
return CCurrency (Dol + Curr.Dollars, Curr.Cents);
}
Следующая программа демонстрирует использование всех трех функций-операторов, определенных выше.
void main()
{
CCurrency Advertising (235, 42);
CCurrency Rent (823, 68);
CCurrency Entertainment (1024, 32);
CCurrency Overhead;
Overhead = Advertising + Rent + Entertainment;
Overhead.PrintAmount ();
Overhead = Overhead + 100;
Overhead.PrintAmount ();
Overhead =100 + Overhead;
Overhead.PrintAmount ();
}
На печать будут выведены значения.
$2083.42
$2183.42
$2283.42
Таким образом, определение трех версий функций-операторов дает возможность применить операцию сложения к двум объектам – объекту и константе, а также к константе и объекту. Четвертая возможная комбинация из двух констант дает стандартную операцию сложения. Далее в параграфе «Конструкторы преобразования» рассмотрена технология создания специального конструктора, исключающего две версии функции operator+ из класса CCurrency.
Усовершенствование класса CCurrency
Класс CCurrency можно усовершенствовать, добавив средства для обработки отрицательных значений денежных сумм и перегрузив другие операторы (обычно при присваивании отрицательной суммы результат непредсказуем). Можно определить функции-операторы для операции вычитания двух объектов или объекта и константы, а также для операций умножения или деления объекта на константу.
При определении таких функций избегайте преобразований сумм долларов и центов в одно значение типа long, хранящееся как общее количество центов. Это упрощает выполнение арифметических действий, но повышает вероятность переполнения и уменьшает максимальное значение суммы долларов.