Операторы перегрузки как функция-член или функция, не являющаяся членом (другом)? - PullRequest
10 голосов
/ 15 декабря 2009

В настоящее время я создаю служебный класс, в котором будут перегружены операторы.Каковы плюсы и минусы в том, чтобы делать их членами или не членами (friend)?Или это вообще имеет значение?Может быть, есть лучшая практика для этого?

Ответы [ 6 ]

20 голосов
/ 08 января 2010

Я бы выбрал «Стандарты кодирования C ++: 101 правила, руководящие указания и рекомендации»: если вы можете сделать это как функцию, не являющуюся членом, сделайте это как функцию, не являющуюся членом (в том же пространстве имен). *

Одна из причин: лучше работает с неявным преобразованием типов. Пример: у вас есть сложный класс с перегруженным оператором *. Если вы хотите написать 2.0 * aComplexNumber, вам нужно, чтобы оператор * был функцией, не являющейся членом.

Другая причина: меньше сцепления. Не-функции-функции менее тесно связаны, чем функции-члены. Это почти всегда хорошо.

16 голосов
/ 15 декабря 2009

Каждый оператор имеет свои соображения. Например, оператор << (при использовании для вывода потока, а не смещения битов) получает ostream в качестве первого параметра, поэтому он не может быть членом вашего класса. Если вы реализуете оператор сложения, вы, вероятно, захотите воспользоваться преимуществами автоматического преобразования типов с обеих сторон, поэтому вы также будете использовать не-член и т. Д. * </p>

Что касается разрешения специализации с помощью наследования, то обычным способом является реализация оператора, не являющегося членом, в терминах функции виртуального члена (например, оператор << вызывает виртуальную функцию print () для передаваемого объекта).

4 голосов
/ 15 декабря 2009

Если вы планируете реализовать потоковые операторы (<< и >>), то они будут методами, не являющимися членами, поскольку ваш объект находится слева от оператора.

Если вы планируете реализовать ->, () или [], то это естественные методы-члены.

Для остальных (сравнительных и математических) вы должны проверить Boost.Operators , это действительно помогает.

Например, если вы хотите реализовать следующие операторы:

MyClass& MyClass::operator+=(int);
MyClass operator+(const MyClass&, int);
MyClass operator+(int, const MyClass&);

Вам нужно только написать:

class MyClass: boost::operator::addable<MyClass,int> // no need for public there
{
public:
  MyClass& operator+=(int);
private:
};

2 operator+ будут автоматически сгенерированы как не члены, что позволит вам воспользоваться автоматическими конверсиями. И они будут эффективно реализованы в терминах operator+=, поэтому вы пишете код только один раз.

3 голосов
/ 15 декабря 2009

Если вы реализуете op, то, скорее всего, вам нужно реализовать op =. То есть, если вы перегружаете оператор +, то вы должны реализовать + =. Убедитесь, что вы возвращаете const объекту, если вы выполняете постинкрементный или перегрузочный оператор +. Таким образом, если вы перегружаете оператор +, то реализуйте его как оператор, не являющийся членом, и используйте оператор + = внутри него. Например,

const A operator+(const A& lhs, const A& rhs)
{
   A ret(lhs);
   ret += rhs;
   return ret;
}
2 голосов
/ 15 декабря 2009

Для бинарных операторов одним из ограничений функций-членов является то, что левый объект должен иметь тип вашего класса. Это может ограничить использование оператора симметрично.

Рассмотрим простой класс строк:

class str
{
public:
    str(const char *);
    str(const str &other);
};

Если вы реализуете operator + как функцию-член, тогда как str("1") + "2" будет компилироваться, "1" + str("2") не будет компилироваться.

Но если вы реализуете operator + как функцию, не являющуюся членом, оба эти утверждения будут допустимы.

0 голосов
/ 15 декабря 2009

Нет ничего лучше, чем лучшие практики, но это зависит от оператора, которого вы перегружаете.

Например,

  1. >> и << </strong> не могут быть перегружены как функции-члены.

  2. Предположим, вы хотите сделать так: obj1 = 2 * obj2 , затем перейдите к функция, не являющаяся членом .

При перегрузке бинарного оператора функция-член принимает только 1 параметр (вызывающий объект передается косвенно), тогда как функция, не являющаяся членом, принимает 2 параметра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...