Унарный и бинарный операторы проверки на равенство
Подскажите, почему оператор проверки на равенство может быть как членом класса (унарным), так и внешним (бинарным)?
bool T::operator==(const T& t);
bool operator==(const T& t1, const T& t2);
Ответы (2 шт):
Ну, например...
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.
Оператор сравнения, определенный вне класса, определяет общее правило сравнения для всех его экземпляров и экземпляров производных классов. Если имеем:
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, и, может быть, какие то операторы, определенные в классах окажутся не нужными, и можно будет убрать их с интерфейса(разгрузить интерфейс).
Есть еще причина, которая делает целесообразным определение оператора вне класса. Допустим есть класс коробок и класс продуктов, которые нужно складывать в коробки.
- Для класса Коробка существенны его размеры, их всегда выбирают
по размерам, поэтому целесообразно в нем иметь
operator==(это имеет прямое отношение к его абстракции). - А вот продукты могут быть такие, что для них важны многие
характеристики, но клиентам не нужно их проверять на равенство,
поэтому при абстрагировании нам
operator==становится как бы избыточным. Но для тех, кто контролирует качество содержимого в ящиках(какой продукт в какой ящик должен попадать), должно существовать правило сравнения, поэтому для них отдельно пишется это правило. Таким образомoperator==становится определенным вне класса, из за логических сооброжений.