У меня есть вопрос об операторах c ++, который, я надеюсь, найдет здесь ответ.Краткая версия вопроса есть в названии, но если есть какие-то сомнения относительно того, что я действительно спрашиваю, вот длинная версия.
операторы c ++ могут быть перегружены, так что становится возможным писать вещикак это:
MyClass a(1), b(2);
Myclass c = a + b;
Насколько я понимаю, типичный способ реализации выглядит следующим образом:
class MyClass
{
private:
int val;
public:
explicit MyClass(int _val);
MyClass operator+(MyClass const& other) const;
MyClass operator+(int i) const;
};
Который в этом случае также включает перегрузку с типом int
, что позволяет писать такие вещи:
MyClass a(1);
Myclass b = a + 2;
Но не так:
MyClass a(1);
Myclass b = 2 + a;
, потому что это будет похоже на вызов 2.operator+(a)
и 2
isnне объект.Поскольку программисты хотели бы перегружать операторы таким образом, чтобы это было возможно, существует второй способ их реализации, который будет выглядеть следующим образом:
class MyClass
{
private:
int val;
public:
explicit MyClass(int _val);
friend MyClass operator+(MyClass const& lhs, MyClass const& rhs);
friend MyClass operator+(int lhs, MyClass const& rhs);
friend MyClass operator+(MyClass const& lhs, int rhs);
};
, который допускает все три типа дополнений.
Теперь, что меня беспокоит: что, если мы реализуем оба одновременно?Как компилятор решает, использовать ли оператор-член или глобальный оператор?
Чтобы быть справедливым, какой оператор вызывается, не имеет значения в любой разумной реализации, и они не должны ни возвращать разные вещи, ниимеют разные побочные эффекты, но я попытался реализовать это, чтобы увидеть, что происходит:
class MyClass
{
private:
int val;
public:
explicit MyClass(int _val) : val(_val){}
MyClass operator+(MyClass const& other) const
{
cout << "Call to member operator+ for MyClass+MyClass" << endl;
return MyClass(val + other.val);
}
MyClass operator+(int other) const
{
cout << "Call to member operator+ for MyClass+int" << endl;
return MyClass(val + other);
}
friend MyClass operator+(MyClass const& lhs, MyClass const& rhs)
{
cout << "Call to global operator+ for MyClass+MyClass " << endl;
return MyClass(lhs.val + rhs.val);
}
friend MyClass operator+(int lhs, MyClass const& rhs)
{
cout << "Call to global operator+ for int+MyClass " << endl;
return MyClass(lhs + rhs.val);
}
friend MyClass operator+(MyClass const& lhs, int rhs)
{
cout << "Call to global operator+ for MyClass+int " << endl;
return MyClass(lhs.val + rhs);
}
};
int main() {
MyClass a(1), b(2);
int i(3);
MyClass r_0 = a.operator+(b);
MyClass r_1 = a.operator+(i);
MyClass r_2 = operator+(a,b);
MyClass r_3 = operator+(a,i);
MyClass r_4 = operator+(i,a);
MyClass r_5 = a + b;
MyClass r_6 = a + i;
MyClass r_7 = i + a;
return 0;
}
, который компилирует и печатает
Call to member operator+ for MyClass+MyClass
Call to member operator+ for MyClass+int
Call to global operator+ for MyClass+MyClass
Call to global operator+ for MyClass+int
Call to global operator+ for int+MyClass
Call to global operator+ for MyClass+MyClass
Call to global operator+ for MyClass+int
Call to global operator+ for int+MyClass
Я бы хотел подумать, что все в этомзаконно и что глобальный оператор имеет приоритет над членом-участником, но единственное, что я мог найти в Интернете, казалось, предполагало, что эти добавления были неоднозначными вызовами, так ли это на самом деле или я просто смотрю на неопределенное поведение здесь?