27. Отдавайте предпочтение каноническим формам арифметических операторов и операторов присваивания

27. Отдавайте предпочтение каноническим формам арифметических операторов и операторов присваивания

Резюме

Если можно записать а+b, то необходимо, чтобы можно было записать и a+=b. При определении бинарных арифметических операторов одновременно предоставляйте и их присваивающие версии, причем делайте это с минимальным дублированием и максимальной эффективностью.

Обсуждение

В общем случае для некоторого бинарного оператора @ (+, -, * и т.д.) вы должны также определить его присваивающую версию, так чтобы a@=b и a=a@b имели один и тот же смысл (причем первая версия может быть более эффективна). Канонический способ достижения данной цели состоит в определении @ посредством @= следующим образом:

T& T::operator@=(const T&) {

 // ... реализация ...

 return *this;

}

T operator@(const T& lhs, const T& rhs) {

 T temp(lhs);

 return temp @= rhs;

}

Эти две функции работают в тандеме. Версия оператора с присваиванием выполняет всю необходимую работу и возвращает свой левый параметр. Версия без присваивания создает временную переменную из левого аргумента, и модифицирует ее с использованием формы оператора с присваиванием, после чего возвращает эту временную переменную.

Обратите внимание, что здесь operator@ — функция-не член, так что она обладает желательным свойством возможности неявного преобразования как левого, так и правого параметра (см. рекомендацию 44). Например, если вы определите класс String, который имеет неявный конструктор, получающий аргумент типа char, то оператор operator+(const String&, const String&), который не является членом класса, позволяет осуществлять операции как типа char+String, так и String+char; функция-член String::operator+(const String&) позволяет использовать только операцию String+char. Реализация, основной целью которой является эффективность, может определить ряд перегрузок оператора operator@, не являющихся членами класса, чтобы избежать увеличения количества временных переменных в процессе преобразований типов (см. рекомендацию 29).

Также делайте не членом функцию operator@= везде, где это возможно (см. рекомендацию 44). В любом случае, все операторы, не являющиеся членами, должны быть помещены в то же пространство имен, что и класс T, так что они будут легко доступны для вызывающих функций при отсутствии каких-либо сюрпризов со стороны поиска имен (см. рекомендацию 57).

Как вариант можно предусмотреть оператор operator@, принимающий первый параметр по значению. Таким образом вы обеспечите неявное копирование компилятором, что обеспечит ему большую свободу действий по оптимизации:

T& operator@=(T& lhs, const T& rhs) {

 // ... реализация ...

 return lhs;

}

T operator@(T lhs, const T& rhs) { // lhs передано по значению

 return lhs @= rhs;

}

Еще один вариант — оператор operator@, который возвращает const-значение. Эта методика имеет то преимущество, что при этом запрещается такой не имеющий смысла код, как a+b=c, но в этом случае мы теряем возможность применения потенциально полезных конструкций наподобие а = (b+c).replace(pos, n, d). А это весьма выразительный код, который в одной строчке выполняет конкатенацию строк b и с, заменяет некоторые символы и присваивает полученный результат переменной а.

Примеры

Пример. Реализация += для строк. При конкатенации строк полезно заранее знать длину, чтобы выделять память только один раз:

String& String::operator+=( const String& rhs ) {

 // ... Реализация ...

 return *this;

}

String operator+( const String& lhs, const String& rhs ) {

 String temp; // изначально пуста

 // выделение достаточного количества памяти

 temp.Reserve(lhs.size() + rhs.size());

 // Конкатенация строк и возврат

 return (temp += lhs) += rhs;

}

Исключения

В некоторых случаях (например, оператор operator*= для комплексных чисел), оператор может изменять левый аргумент настолько существенно, что более выгодным может оказаться реализация оператора operator*= посредством оператора operator*, а не наоборот.

Ссылки

[Alexandrescu03a] • [Cline99] §23.06 • [Meyers96] §22 • [Sutter00] §20

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

3.3 Сводка операторов

Из книги C++ автора Хилл Мюррей

3.3 Сводка операторов Операторы С++ систематически и полностью изложены в #с.9, прочитайте, пожалуйста, этот раздел. А здесь приводится краткая сводка и некоторые примеры.Синтаксис оператора – оператор: описание (*список_операторов opt*) выражение optif оператор if ( выражение )


Список операторов

Из книги Блоги. Новая сфера влияния автора Попов Антон Валерьевич

Список операторов «Яндекс» позволяет вести поиск в отдельных элементах страницы или в связанной с ней информации. Обратите внимание на то, что при использовании операторов, в которых как параметр задается имя хоста (таких как url, host и др.), должно указываться главное


Группировка операторов

Из книги Delphi. Учимся на примерах автора Парижский Сергей Михайлович

Группировка операторов Операторы можно группировать, заключая их в круглые скобки.


Порядок выполнения операторов

Из книги Microsoft Visual C++ и MFC. Программирование для Windows 95 и Windows NT автора Фролов Александр Вячеславович

Порядок выполнения операторов В сложных выражениях операторы выполняются в следующем порядке:1. ( ).2. not.3. *, /, div, mod, and, shl, shr, as.4. +, –, or, xor.5. =, <>, <, >, <=, >=, in,


Перегрузка операторов

Из книги О чём не пишут в книгах по Delphi автора Григорьев А. Б.

Перегрузка операторов Си++ позволяет вам легко вводить новые типы данных. Так, например, вы можете определить класс для работы с комплексными числами или числами в полярной системе координат. Естественно, что удобнее всего проводить вычисления с объектами таких классов


Приоритет операторов

Из книги HTML 5, CSS 3 и Web 2.0. Разработка современных Web-сайтов автора Дронов Владимир

Приоритет операторов Последний вопрос, который мы здесь разберем, — приоритет операторов. Как мы помним, приоритет влияет на порядок, в котором выполняются операторы в выражении.Пусть имеется следующее выражение:a = b + c — 10;В этом случае сначала к значению переменной b


Приоритет операторов

Из книги VBA для чайников автора Каммингс Стив

Приоритет операторов Последний вопрос, который мы здесь разберем, — приоритет операторов. Как мы помним, приоритет влияет на порядок, в котором выполняются операторы в выражении.Пусть имеется следующее выражение:a = b + c — 10;В этом случае сначала к значению переменной b


Использование операторов

Из книги C++. Сборник рецептов автора Диггинс Кристофер

Использование операторов Процедуры состоят из операторов - наименьших жизнеспособных единиц программного кода. Как правило, операторы занимают по одной строке программного кода, и в каждой строке обычно содержится только один оператор, но, как будет показано немного


Приоритет операторов

Из книги автора

Приоритет операторов Приоритет определяет порядок, в котором операторы и создаваемые ими значения вычисляются в выражении.Когда выражение содержит несколько операторов одного и того же типа, операторы вычисляются слева направо, если только не существует конфликта,


Перегрузка операторов

Из книги автора

Перегрузка операторов С++ позволяет нам перегружать функции, т.е. мы можем объявлять несколько функций с одним именем в одной и той же области видимости, если они имеют различные списки параметров. Кроме того, С++ поддерживает перегрузку операторов, позволяя назначать