Подтвердить что ты не робот

Перегрузка оператора внешним классом

Существует два способа перегрузить операторы для класса С++:

Внутренний класс

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 ;
}

(По-видимому, в С# вы можете использовать только метод "внешнего класса".)

В С++, какой путь является более правильным? Что предпочтительнее?

4b9b3361

Ответ 1

Основной вопрос: "Вы хотите, чтобы преобразования выполнялись по левому параметру оператора?". Если да, используйте свободную функцию. Если нет, используйте член класса.

Например, для оператора +() для строк мы хотим, чтобы выполнялись преобразования, поэтому мы можем сказать такие вещи, как:

string a = "bar";
string b = "foo" + a;

где выполняется преобразование, чтобы превратить char * "foo" в std::string. Поэтому мы приводим оператор +() для строк в свободную функцию.

Ответ 2

Во-первых: два разных способа - это действительно "перегрузка как член" и "перегрузка как нечлен", а вторая имеет два разных способа ее записи (определение класса "внутри друга" и определение внешнего класса), Вызов их "внутри класса" и "внешнего класса" будет вас путать.


Перегрузки для + =, +, - =, - и т.д. имеют специальный шаблон:

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 + и т.д. в качестве друзей в определении класса с помощью трюк Barton-Nackman, потому что из-за причуд шаблонов и перегрузки он не может быть найден иначе.

Ответ 3

В Meyer Effective С++ есть прекрасное обсуждение этой проблемы: в пункте 24 "Объявлять функции, не являющиеся членами, когда преобразования типов должны применяться ко всем параметрам", а в пункте 46 "Определять функции, не являющиеся членами внутри шаблонов, когда преобразования типов желательно".