Я в настоящее время создаю служебный класс, который перегрузит операторы в нем. Что за и против или делают их участником или нечленом (friend
) функции? Или это имеет значение вообще? Возможно, существует лучшая практика для этого?
У каждого оператора есть свои особенности. Например, оператор << (при использовании для потокового вывода, а не для сдвига битов) получает ostream в качестве первого параметра, поэтому он не может быть членом вашего класса. Если вы реализуете оператор сложения, вы, вероятно, захотите воспользоваться преимуществами автоматического преобразования типов с обеих сторон, поэтому вы также будете использовать не-член и т.д ...
Что касается разрешения специализации через наследование распространенным шаблоном является реализация оператора, не являющегося членом, в терминах виртуальной функции-члена (например, operator << вызывает виртуальную функцию print () для передаваемого объекта).
If you plan on implementing streaming operators (<< and >>) then they will be non-members methods because your object is on the left of the operator.
If you plan on implementing ->, () or [] they are naturally member methods.
For the others (comparison and mathematical) you should check out Boost.Operators, it really helps.
For example, if you want to implement the following operators:
MyClass& MyClass::operator+=(int);
MyClass operator+(const MyClass&, int);
MyClass operator+(int, const MyClass&);
You only have to write:
class MyClass: boost::operator::addable<MyClass,int> // no need for public there
{
public:
MyClass& operator+=(int);
private:
};
The 2 operator+
will be automatically generated as non-members which will let you benefit from automatic conversions. And they will be implemented efficiently in term of operator+=
so you write code only once.
Если вы реализуете op, то, скорее всего, вам нужно реализовать op =. т.е. если вы перегружаете оператор +, Убедитесь, что вы возвращаете const объекту, если вы выполняете пост-инкремент или перегрузку оператора +. Итак, если вы перегружаете оператор +, реализуйте его как оператор, не являющийся членом, и используйте внутри него оператор + =. Например,
const A operator+(const A& lhs, const A& rhs)
{
A ret(lhs);
ret += rhs;
return ret;
}
Нет ничего лучше передового опыта, но это зависит от оператора, который вы перегружаете ..
Например,
>> и << не могут быть перегружены как функции-члены.
Предположим, вы хотите сделать следующее: obj1 = 2 * obj2 , затем перейдите к функции, не являющейся членом .
Для перегрузка бинарного оператора функция-член принимает только 1 параметр (вызывающий объект передается неявно), тогда как функция, не являющаяся членом, принимает 2 параметра.
Для бинарных операторов одно ограничение функций-членов состоит в том, что левый объект должен быть вашего типа класса. Это может ограничить использование оператора симметрично.
Рассмотрим простой строковый класс:
class str
{
public:
str(const char *);
str(const str &other);
};
Если вы реализуете оператор + как функцию-член, а str («1») + «2»
будет компилироваться, «1» + str ( «2»)
не будет компилироваться.
Но если вы реализуете operator + как функцию, не являющуюся членом, тогда оба этих оператора будут допустимы.
Я бы пошел с «стандартами кодирования C ++: 101 правила, руководящие принципы и лучшие практики»: если вы можете сделать это как не -Мебельная функция, сделайте это как функцию не-член (в том же пространстве имен).
Одна из причин: он работает лучше с неявным преобразованием типа. Пример: у вас есть сложный класс с перегруженным оператором *. Если вы хотите написать 2.0 * Apomplexnumber, вам нужен оператор *, чтобы быть функцией не-члена.
Еще одна причина: меньше муфты. Не члены функции менее тесно связаны с функциями элементов. Это почти всегда хорошо.