Унарный и бинарный операторы проверки на равенство

Подскажите, почему оператор проверки на равенство может быть как членом класса (унарным), так и внешним (бинарным)?

bool T::operator==(const T& t);
bool operator==(const T& t1, const T& t2);

Ответы (2 шт):

Автор решения: Harry

Ну, например...

bool T::operator==(const T& a);

и

T::T(int);

Вы никак не сможете выполнить проверку

T t;
if (5 == t)

в то время как для случая свободного оператора - запросто, благодаря приведению типа...

Вот живой пример:

struct T
{
    int i;

    T(int i):i(i){}
    bool operator==(const T& t) { return t.i == i; }
};

// bool operator==(const T& t, const T& u) { return t.i == u.i; }


int main()
{
    T t(5);
    cout << (4 == t);
}

Попробуйте скомпилировать - ничего не выйдет. Но уберите комментарий - и все заработает.

Так понятно?

Оператор как член класса требует, чтобы первым аргументом был однозначно объект этого класса, без каких-либо приведений типа etc.

→ Ссылка
Автор решения: AR Hovsepyan

Оператор сравнения, определенный вне класса, определяет общее правило сравнения для всех его экземпляров и экземпляров производных классов. Если имеем:

struct MyCont {  
   //...        
    bool operator ==(const MyCont& v)
    {
        //...
    }
};

То, operator == предназначен, чтобы сравнить обьекты MyCont(левый операнд оператора) с обьектами этого типа или производными типами, так, что MyCont& могла ссылаться на них(правый операнд оператора). Теперь напишем производный тип и напишем для него свой оператор:

//сравнивается не так, как MyCont
struct MyVector : public MyCont {
    //...        
    bool operator ==(const MyVector& v)
    {
        //...
    }
};
//и создадим экземпляры 
MyCont base(5);
MyVector v1(4), v2(4);

Для MyVector::operator== действуют те же правила, поэтому мы можем сравнивать так:

base == v1; // правильно: MyCont::operator==
base == v2; 
v1 == v2;   //правильно:  MyVector::operator==

Но не сможем выполнить сравнение v1 == base или v2 == base, потому что справа обьект не того же типа или производнего от него типа. Но если определим свободный оператор:

bool operator ==(const MyCont& v1, const MyCont& v2)
{
   //...
}

То этот оператор определит общее правило сравнения для всех типов, которые неявно могут преобразоваться в MyCont, поэтому можем без проблем выполнить: v1 == base или v2 == base, и, может быть, какие то операторы, определенные в классах окажутся не нужными, и можно будет убрать их с интерфейса(разгрузить интерфейс).

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

  1. Для класса Коробка существенны его размеры, их всегда выбирают по размерам, поэтому целесообразно в нем иметь operator== (это имеет прямое отношение к его абстракции).
  2. А вот продукты могут быть такие, что для них важны многие характеристики, но клиентам не нужно их проверять на равенство, поэтому при абстрагировании нам operator== становится как бы избыточным. Но для тех, кто контролирует качество содержимого в ящиках(какой продукт в какой ящик должен попадать), должно существовать правило сравнения, поэтому для них отдельно пишется это правило. Таким образом operator== становится определенным вне класса, из за логических сооброжений.
→ Ссылка