Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_С++_последная.doc
Скачиваний:
42
Добавлен:
07.05.2019
Размер:
876.54 Кб
Скачать

8.1.2. Перегрузка операций методами класса

У методов один параметр – текущий объект – определен по умолчанию. Унарные операции выполняются для текущего объекта, который и является единственным аргументом. Поэтому унарные операции, перегружаемые как методы класса, не имеют параметров. Прототип унарной операции, реализованной как метод класса, выглядит так:

тип operator@();

где @ – символ операции. Возвращаемое значение может быть любого типа, в том числе и определяемого класса. Операция может возвращать значение, ссылку или указатель на объект. Разрешается указывать void на месте типа возвращаемого значения.

Постфиксные операции инкремента и декремента являются исключением из этого правила. Чтобы отличить постфиксную операцию от префиксной, в постфиксной форме задается фиктивный параметр типа int, который реально не используется.

Префиксная форма инкремента (и декремента) должна иметь прототип:

тип& operator@();

Постфиксная операция инкремента (и декремента) должна иметь прототип:

тип operator@(int);

Тип – это «имя_класса», в котором определяется операция.

Прототип бинарной операции имеет один аргумент и выглядит таким образом:

тип operator@(параметр);

Параметры разрешается передавать любым удобным нам способом: по значению, по ссылке или по указателю. Возвращать метод-операция тоже может значение, указатель или ссылку на объект, в том числе и своего класса. Разрешается указывать void на месте типа возвращаемого значения.

При реализации метода-операции вне класса требуется в заголовке обычным образом указывать префикс-имя класса:

тип класс::operator@() // унарная операция

тип класс::operator@(параметр) // бинарная операция

Вызов унарной операции для объекта имеет форму;

@объект;

объект@;

в зависимости от того, какой вид операции используется – префиксный или постфиксный. Функциональный вызов для префиксной операции имеет форму:

объект.operator@()

Для постфиксной операции в функциональной форме вызова нужно задавать фиктивный аргумент:

объект.operator@(0)

Функциональная форма вызова для бинарной операции, определенной как метод класса, выглядит так:

объект.operator@(аргумент)

Операции присваивания являются бинарными операциями, поэтому должны иметь один аргумент. Если операция присваивания operator= не реализуется явным образом, она создается автоматически по умолчанию. Для любого класса автоматически создаваемая операция присваивания имеет прототип:

класс& operator=(const класс &r)

Допускается реализовать операцию присваивания с параметром и возвращаемым результатом не своего класса; разрешается передавать параметр любым способом; возвращать можно не ссылку, а значение или указатель – все зависит от потребностей задачи.

Другие операции с присваиванием автоматически не создаются. Функции-операции с присваиванием обычно должны возвращать ссылку на текущий объект. Любой метод, возвращающий неконстантную ссылку, можно использовать многократно:

Money& Money::operator+=(const Money &b)

Любая внешняя функция, определенная как «друг» класса, имеет неограниченный доступ к любым элементам класса, в том числе и к закрытым. Для того чтобы внешняя функция стала другом класса, необходимо в интерфейсе класса задать ее прототип, добавив впереди слово friend, например:

friend Money operator*(const long double &a, const Money &b);

При реализации функции слово friend писать запрещается. Не указывается также и префикс класса.

В частности, операции ввода/вывода operator>> и operator<< практически всегда реализуются как внешние дружественные функции. Например, для класса Two с двумя полями х и у целого типа эти функции могут выглядеть так:

ostream& operator<<(ostream& t, const Two &r)

{ return (t << '(' << r.x << '.' << r.y << ')'); }

istream& operator>>(istreams t, Two &r)

{ t >> r.x >> r.y; return t; }

Пример перегрузки операций методами класса и дружественными функциями показан в листинге следующем листинге программы.

class F

{ int f; int m;

public:

F(int t, int r = 0) // конструктор

{ f = t; m = г; }

F& operator++() // префиксный инкремент

{ f++; return *this; }

F operator++(int) // постфиксный инкремент

{ F t = *this; f++; return t; }

F& operator+=(const F& r) // сложение с присваиванием

{ f+=r.f; m+=r.m; return *this; }

// дружественные функции

friend F operator+(const F &1, const F &r);

friend ostream& operator<<(ostream& t. const F &r)

friend istream& operator>>(istreams t. F Sr)

};

// реализация дружественных функций

F operator+(const F &l, const F &r)

{ F t = 1; t+=r; return t; }

// дружественные функции ввода/вывода

ostream& operator<<(ostream& t, const F &r)

{ return (t << r.f << '/' << r.m); }

istream& operator>>(istreams t. F &r)

{ t >> r.f >> r.m; return t; } \