Урок 134. Перегрузка операторов через методы класса

   ⁄ 

 Обновлено 11 Апр 2018  ⁄ 

⁄   135

Перегрузка операторов через методы класса очень похожа на перегрузку операторов через дружественные функции. Но, при перегрузке оператора через метод класса, левым операндом становится неявный объект, на который указывает скрытый указатель *this.

Вспомним как выглядит перегрузка оператора через дружественную функцию:

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

  Перегружаемый оператор определяется как метод класса вместо дружественной функции (Dollars::operator+ вместо friend operator+).

  Левый параметр из функции перегрузки выбрасывается, вместо него — неявный объект, на который указывает this*.

  Внутри тела функции перегрузки все ссылки на левый параметр могут быть удалены (например, dollars.m_dollars становится m_dollars, который неявно ссылается на текущий объект с помощью указателя *this).

Теперь та же перегрузка оператора +, только уже через метод класса:

Обратите внимание, использование оператора + не изменяется (в обоих случаях, dollars1 + 3), но реализация отличается. Наша дружественная функция с двумя параметрами становится методом класса с одним параметром, причем левый параметр в перегрузке через дружественную функцию (&dollars) в перегрузке через метод класса становится неявным объектом, на который указывает указатель *this.



Рассмотрим детальнее, как обрабатывается выражение dollars1 + 3.

В перегрузке через дружественную функцию выражение dollars1 + 3 приводит к вызову функции operator+(dollars1, 3). Здесь два параметра.

В перегрузке через метод класса выражение dollars1 + 3 приводит к вызову dollars1.operator+(3). Обратите внимание, здесь уже один явный параметр, а dollars1 используется как префикс к operator+. Этот префикс компилятор неявно конвертирует в скрытый левый параметр, на который указывает указатель *this. Таким образом, dollars1.operator+(3) становится вызовом operator+(&dollars1, 3), что почти идентично перегрузке через дружественную функцию.

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

Не всё может быть перегружено через дружественные функции

Операторы присваивания (=), индекса ([]), вызова функции (()) и выбора члена (->) перегружаются через методы класса – это требование языка C++.

Не всё может быть перегружено через методы класса

В уроке о перегрузке операторов ввода и вывода мы перегрузили оператор вывода << для класса Point через дружественную функцию:

Однако через метод класса перегрузить оператор << мы не сможем. Почему? Потому что при перегрузке через метод класса в качестве левого операнда используется текущий объект. В этом случае левым операндом является объект типа std::ostream. std::ostream является частью стандартной библиотеки C++. Мы не можем использовать std::ostream в качестве левого неявного параметра, на который бы указывал скрытый указатель *this, так как *this может указывать только на текущий объект текущего класса, члены которого мы можем изменить. Поэтому, перегрузка оператора << должна осуществляться через дружественную функцию.

Аналогично, хотя мы можем перегрузить operator+(Dollars, int) через метод класса (как мы делали выше), мы не можем перегрузить operator+(int, Dollars) через метод класса, поскольку int теперь является левым оператором, на который указатель *this указывать не может.

Перегрузка операторов через методы класса не используется, если левый операнд не является классом (например, int), или это класс, который мы не можем изменить (например, std::ostream).

Какой способ перегрузки и когда следует использовать?

В большинстве случаев язык C++ позволяет выбирать самостоятельно способ перегрузки операторов.

Но, при работе с бинарными операторами, которые не изменяют левый операнд (например, operator+), обычно используется перегрузка через обычную или дружественную функции, поскольку такая перегрузка работает для всех типов данных параметров (даже если левый операнд не является объектом класса или является объектом класса, который изменить нельзя). Перегрузка через обычную/дружественную функцию имеет дополнительное преимущество «симметрии», так как все операнды становятся явными параметрами (а не как у перегрузке через метод класса, когда левый операнд становится неявным объектом, на который указывает *this).

При работе с бинарными операторами, которые изменяют левый операнд (например, operator+=), обычно используется перегрузка через методы класса. В этих случаях левым операндом всегда является объект класса, на который указывает скрытый указатель *this.

Унарные операторы обычно тоже перегружаются через методы класса, так как в таком случае, параметры не используются вообще.



Итого:

  Для операторов присваивания (=), индекса ([]), вызова функции (()) или выбора члена (->) используйте перегрузку через методы класса.

  Для унарных операторов используйте перегрузку через методы класса.

  Для перегрузки бинарных операторов, которые изменяют левый операнд (например, operator+=) используйте перегрузку через методы класса, если это возможно.

  Для перегрузки бинарных операторов, которые не изменяют левый операнд (например, operator+) используйте перегрузку через обычные/дружественные функции.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (1 оценок, среднее: 5,00 из 5)
Загрузка...
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

ПОДПИСЫВАЙТЕСЬ

НА КАНАЛ RAVESLI В TELEGRAM

@ravesli

ПОДПИСАТЬСЯ БЕСПЛАТНО