Правила программирования на Си и Си++

Перегруженные операции должны работать точно так же, как они работают в Си


Главной новой проблемой здесь являются адресные типы lvalue и rvalue. Выражения типа lvalue

легко описываются в терминах Си++: они являются просто ссылками. Компилятор Си, вычисляя выражение, выполняет операции по одной за раз в порядке, определяемом правилами сочетательности и старшинства операций. Каждый этап в вычислениях использует временную переменную, полученную при предыдущей операции. Некоторые операции генерируют "rvalue" —

действительные объекты, на самом деле содержащие значение. Другие операции создают "lvalue" —

ссылки на объекты. (Кстати, "l" и "r" используются потому, что в выражении l=r

слева от =

генерируется тип lvalue. Справа образуется тип rvalue).

Вы можете сократить эффект неожиданности для своего читателя, заставив свои перегруженные операции-функции работать тождественно их эквивалентам на Си в пределах того, что они могут. Далее описано, как работают операции Си и как имитировать их поведение:

·

Операции присваивания (=, +=, -= и т.д.) и операции автоинкремента и автодекремента (++, --) требуют операндов типа lvalue для адресата — части, которая изменяется. Представьте ++ как эквивалент для +=1, чтобы понять, почему эта операция в той же категории, что и присваивание.

В перегруженных операциях функций-членов указатель this на самом деле является lvalue, поэтому здесь не о чем беспокоиться. На глобальном уровне левый операнд перегруженной бинарной операции присваивания (и единственный операнд перегруженной унарной операции присваивания) должен быть ссылкой.

· Все другие операции могут иметь операнды как типа lvalue,

так и rvalue.

Используйте ссылку на объект типа const для всех операндов. (Вы могли бы передавать операторы по значению, но обычно это менее эффективно).

· Имена переменных составного типа (массивов) создают типы rvalue —

временные переменные типа указателя на первый элемент, после инициализации на него и указывающие. Заметьте, что неверно представление о том, что вы не можете инкрементировать имя массива из-за того, что оно является константой. Вы не можете инкрементировать имя массива, потому что оно имеет тип rvalue, а все операции инкремента требуют операндов типа lvalue.


· Имена переменных несоставного типа дают lvalue.
· Операции *, - и [] генерируют lvalue, когда относятся к несоставной переменной, иначе они работают подобно именам составных переменных. Если y не является массивом, то x-y создает тип lvalue, который ссылается на этого поле данных. Если y —
массив, то x-y генерирует тип rvalue, который ссылается на первую ячейку этого массива.
В Си++ перегруженные * и [] должны возвращать ссылки на указанный объект. Операция operator- таинственна. Правила по существу заставляют вас использовать ее таким же образом, как вы делали бы это в Си. Операция - рассматривается как унарная с операндом слева от нее. Перегруженная функция должна возвращать указатель на что-нибудь, имеющее поля — структуру,
класс или объединение. Компилятор будет затем использовать такое поле для получения lvalue или rvalue. Вы не можете перегрузить .(точку).
· Все другие операнды генерируют тип rvalue.
Эквивалентные перегруженные операции должны возвращать объекты, а не ссылки или указатели.

Содержание раздела