Когда перегрузка операторов это плохо? [закрыт]

188
28 октября 2019, 14:40

Перегрузка операторов крайне удобная возможность языка С++. Ведь можем написать:

#include <iostream>
class Point2i
{
  int x;
  int y;
  public:
    Point2i(int x, int y):x(x),y(y){}
    bool operator==(const Point2i &  other)
    {
        return x == other.x && y == other.y ? true:false;
    }
};
int main() {
   Point2i p1(12, 3);
   Point2i p2(1, -11);
   if(p1 == p2)
      std::cout<<"p1==p2"<<'\n';
   return 0;
}

Скорее всего бывают случаи когда это не уместно.

Когда перегрузка операторов это плохо?

P.S Имеется в виду о любых операторах

Answer 1

В качестве эпиграфа:

— Нужно потреблять, но не злоупотреблять, — поучительным тоном заметил Арамис.
А. Дюма, "Три мушкетера"

Это очень плохо, когда нарушается семантика (попросту, смысл) оператора.

Например, возьмем ваши точки. Что такое их вычитание или умножение? (если это точки, а не двумерные вектора). Или что такое отношение < для точек? хотя никто не мешает вам написать, например, сравнение модулей расстояний от начала координат. Или еще чего - но это будет неочевидное сравнение. А ведь можно написать оператор <, который будет, скажем, выводить суммы всех четырех координат :)

Или, например, то же отношение равенства, как вы написали, но которое возвращает не bool, а считает, скажем, какую-то строку - пусть те же "true" и "false".

Такое применение запутывает всех читающих код, в том числе самого автора.

Есть еще хитрые случаи, связанные с поиском имен, но это уже достаточно большая редкость.

А главное - смотри эпиграф. Ничто не следует использовать только по той причине, что его можно использовать. Вы никогда не видели "картин", которые создают малолетки, научившиеся какой-то возможности в фотошопе, и использующие ее только потому, что "вот как я умею!" (кстати, грешат этим и взрослые, особенно в кино...)? Или тексты, изобилующие одновременно 20 шрифтами? :) Вот просто не делайте такие программы, и все будет хорошо :)

P.S. Кстати, не забывайте, что ассоциативность и приоритеты операторов сохраняются, так что сделать, скажем, оператор ^ оператором возведения в степень оказывается, гм... не очень умной идеей.

Answer 2

Конкретный пример языковой неконсистентности, потенциально приводящий к эпическим фейлам. В С++ для встроенных логических операторов вычисление правого операнда не производится, если после вычисления значения левого операнда результат операции определен. Например в Is_Good() && Do_Work() функция Do_Work не будет вызвана, если Is_Good возвращает false. Однако для перегруженных логических операторов это не соблюдается! Кроме того, операнды перегруженного логического оператора могут вычисляться вообще в любом порядке, так что в этом примере при использовании tribool функция Do_Work внезапно вызывается даже до Is_Good:

#include <boost/logic/tribool.hpp>
#include <boost/logic/tribool_io.hpp>
#include <iostream>
template<typename x_Bool> class t_Fancy
{
    private: x_Bool Is_Good(void) const
    {
        ::std::cout << "is not good!" << ::std::endl;
        return false;
    }
    // must be called only when Is_Good returns true!
    private: x_Bool Do_Work(void) const
    {
        ::std::cout << "FAIL" << ::std::endl;
        return false;
    }
    public: x_Bool Work(void) const
    {
        return Is_Good() && Do_Work();
    }
};
int main()
{
    ::std::cout << ::std::boolalpha << t_Fancy<bool>{}.Work() << ::std::endl;
    ::std::cout << ::std::boolalpha << t_Fancy<::boost::tribool>{}.Work() << ::std::endl;
    return 0;    
}

online compiler

is not good!
false
FAIL
is not good!
false

READ ALSO
Инициализация класса массивом

Инициализация класса массивом

у меня есть следующий класс со следующим конструктором:

151
Socket Android Java

Socket Android Java

Пишу серверное приложениеУ меня сервер написан на java а клиент android приложение

164