13.6 – Перегрузка унарных операторов +, - и !
Перегрузка унарных операторов
В отличие от операторов, которые мы рассматривали до сих пор, операторы положительный (+
), отрицательный (-
) и логическое НЕ (!
) являются унарными операторами, что означает, что они работают только с одним операндом. Поскольку они работают только с объектом, к которому они применяются, перегрузки унарных операторов обычно реализуются как функции-члены. Операнды у всех трех реализованы одинаково.
Давайте посмотрим, как мы реализуем operator-
в классе Cents
, который мы использовали в предыдущем примере:
#include <iostream>
class Cents
{
private:
int m_cents;
public:
Cents(int cents) { m_cents = cents; }
// Перегрузка -Cents как функция-член
Cents operator-() const;
int getCents() const { return m_cents; }
};
// обратите внимание: эта функция является функцией-членом!
Cents Cents::operator-() const
{
return -m_cents;
}
int main()
{
const Cents nickle{ 5 };
std::cout << "A nickle of debt is worth " << (-nickle).getCents() << " cents\n";
return 0;
}
Всё просто. Наш перегруженный оператор отрицательный (-
) – это унарный оператор, реализованный как функция-член, поэтому он не принимает никаких параметров (он работает с объектом *this
). Он возвращает объект Cents
, который является отрицанием исходного значения Cents
. Поскольку operator-
не изменяет объект Cents
, мы можем (и должны) сделать его константной функцией (чтобы ее можно было вызывать для константных объектов Cents
).
Обратите внимание, что нет никакой путаницы между оператором отрицания и оператором минус, поскольку они имеют разное количество параметров.
Вот еще один пример. Оператор !
является оператором логического отрицания – если выражение принимает значение true
, operator!
вернет false
, и наоборот. Обычно это применяется к логическим переменным, чтобы проверить, истинны они или нет:
if (!isHappy)
std::cout << "I am not happy!\n";
else
std::cout << "I am so happy!\n";
Для целых чисел 0 означает false
, а всё остальное – true
, поэтому operator!
применительно к целым числам вернет true
для целочисленного значения 0 и false
в противном случае.
Расширяя эту концепцию, можно сказать, что operator!
должен вычисляться как true
, если состояние объекта – false
, ноль или любое другое состояние инициализации по умолчанию.
В следующем примере показана перегрузка operator-
и operator!
для пользовательского класса Point
:
#include <iostream>
class Point
{
private:
double m_x, m_y, m_z;
public:
Point(double x=0.0, double y=0.0, double z=0.0):
m_x{x}, m_y{y}, m_z{z}
{
}
// Преобразует Point в отрицательный эквивалент
Point operator- () const;
// Возвращает true, если точка установлена в начале координат
bool operator! () const;
double getX() const { return m_x; }
double getY() const { return m_y; }
double getZ() const { return m_z; }
};
// Преобразует Point в отрицательный эквивалент
Point Point::operator- () const
{
return Point(-m_x, -m_y, -m_z);
}
// Возвращает true, если точка установлена в начале координат, иначе false
bool Point::operator! () const
{
return (m_x == 0.0 && m_y == 0.0 && m_z == 0.0);
}
int main()
{
// использовать конструктор по умолчанию для установки в (0.0, 0.0, 0.0)
Point point{};
if (!point)
std::cout << "point is set at the origin.\n";
else
std::cout << "point is not set at the origin.\n";
return 0;
}
Перегруженный operator!
для этого класса возвращает логическое значение true
, если для Point
установлено значение по умолчанию в координате (0,0, 0,0, 0,0). Таким образом, приведенный выше код дает следующий результат:
point is set at the origin.
Небольшой тест
Вопрос 1
Реализуйте перегруженный operator+
для класса Point
.
Ответ
Очевидное решение:
Point Point::operator+ () const { return Point(m_x, m_y, m_z); }
Но поскольку точка, которую мы возвращаем, совпадает с той, над которой мы работаем, следующее также работает:
Point Point::operator+ () const { return *this; }
Обратите внимание, что здесь мы возвращаем копию по значению, а не ссылку на константное значение. Это связано с тем, что пользователи этой функции, вероятно, ожидают, что возвращаемый объект будет изменяемым.