Этот вопрос уже имеет ответ здесь:
Существует два способа перегрузить операторы для класса C++:
class Vector2
{
public:
float x, y ;
Vector2 operator+( const Vector2 & other )
{
Vector2 ans ;
ans.x = x + other.x ;
ans.y = y + other.y ;
return ans ;
}
} ;
class Vector2
{
public:
float x, y ;
} ;
Vector2 operator+( const Vector2& v1, const Vector2& v2 )
{
Vector2 ans ;
ans.x = v1.x + v2.x ;
ans.y = v1.y + v2.y ;
return ans ;
}
(По-видимому, в C# можно только использовать "вне класса" метод.)
В C++, какой путь более корректен? Который предпочтителен?
Основной вопрос: «Вы хотите, чтобы преобразования выполнялись в параметре левой части оператора?» . Если да, воспользуйтесь бесплатной функцией. Если нет, используйте члена класса.
Например, для operator + ()
для строк мы хотим, чтобы преобразования выполнялись, чтобы мы могли сказать такие вещи, как:
string a = "bar";
string b = "foo" + a;
где выполняется преобразование, чтобы превратить char * "foo "
в std :: string
. Итак, мы превращаем operator + ()
для строк в бесплатную функцию.
В Эффективном C ++ Мейера есть прекрасное обсуждение этой проблемы: Правило 24: «Объявите функции, не являющиеся членами, когда преобразование типов должно применяться ко всем параметрам» и Правило 46: «Определите в шаблонах функции, не являющиеся членами, когда требуется преобразование типов».
Во-первых: на самом деле два разных способа - это «перегрузка как элемент» и «перегрузка как не-член», а у последнего есть два разных способа напишите его (определение класса как друга внутри и определение класса вне класса). Называя их «внутри класса» и «вне класса» вы запутаетесь.
Перегрузки для + =, +, - =, - и т.д. имеют специальный шаблон:
struct Vector2 {
float x, y;
Vector2& operator+=(Vector2 const& other) {
x += other.x;
y += other.y;
return *this;
}
Vector2& operator-=(Vector2 const& other) {
x -= other.x;
y -= other.y;
return *this;
}
};
Vector2 operator+(Vector2 a, Vector2 const& b) {
// note 'a' is passed by value and thus copied
a += b;
return a;
}
Vector2 operator-(Vector2 a, Vector2 const& b) { return a -= b; } // compact
Этот шаблон позволяет преобразования, упомянутые в других ответах для аргумента LHS, при этом значительно упрощая реализацию. (Член или не член разрешает преобразования для RHS, когда он передается либо как const &
, либо по значению, как и должно быть.) Конечно, это применимо только тогда, когда вы действительно хотите перегрузить оба + = и +, - = и - и т. д., но это все еще распространено.
Кроме того, иногда вы хотите объявить свою op +, не являющуюся членом, и т. Д. Как друзей в определении класса, используя трюк Бартона-Накмана , потому что из-за особенностей шаблонов и перегрузка, его нельзя найти иначе .