13.6 – Перегрузка унарных операторов +, - и !

Добавлено 18 июля 2021 в 15:44

Перегрузка унарных операторов

В отличие от операторов, которые мы рассматривали до сих пор, операторы положительный (+), отрицательный (-) и логическое НЕ (!) являются унарными операторами, что означает, что они работают только с одним операндом. Поскольку они работают только с объектом, к которому они применяются, перегрузки унарных операторов обычно реализуются как функции-члены. Операнды у всех трех реализованы одинаково.

Давайте посмотрим, как мы реализуем 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;
}

Обратите внимание, что здесь мы возвращаем копию по значению, а не ссылку на константное значение. Это связано с тем, что пользователи этой функции, вероятно, ожидают, что возвращаемый объект будет изменяемым.

Теги

C++ / CppLearnCppОбучениеОператор (программирование)Перегрузка (программирование)Перегрузка операторовПрограммированиеУнарный оператор

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.