Семинар 14 (02.12.2016)
Ссылки, константные ссылки и объекты в сигнатурах методов
Некоторые принципы использования ссылок, константных ссылок, объектов и указателей в сигнатурах методов.
- Если объект не должен изменяться при вызове некоторого метода этого объекта, этот метод должен быть задекларирован как константный (
const
после аргументов метода).
// Пример
class Container {
// ...
int size() const; // получить размер контейнера, содержимое контейнера при этом не меняется.
// ...
};
- Если при передаче объекта в метод или функцию этот объект не должен быть изменен - аргумент должен передаваться как константная ссылка (чтобы избежать копирования объекта).
int calculateSizeOf(const Container & c);
// std::ostream нельзя копировать, поэтому он передается в operator<< и возвращается по ссылке.
// Ссылка неконстантная, потому что в процессе работы меняется состояние потока вывода.
// Объект Container в процессе вывода не изменяется.
std::ostream & operator<<(std::ostream & out, const Container & c);
- Операторы вида
x=
(например,+=
,-=
,&=
,|=
и даже=
) модифицируют первый аргумент и не модифицируют второй. Возвращаемое значение - ссылка на первый аргумент (на "самого себя"). Записьa += b;
можно понимать какa.operator+=(b)
. Общий вид сигнатуры этих операторов следующий:
class Container {
// ...
Container & operator=(const Containter & another) {
// ...
return * this;
}
Contaiter & operator+=(const Containter & another);
// ...
};
- Операторы вида
+
,-
,&
,|
,==
создают новый объект из двух существующих, поэтому тип возвращаемого значения - объект, а не ссылка. Ни один из аргументов при этом не должен модифицироваться, поэтому -const
два раза.
class Container {
// ...
Container operator+(const Containter & another) const;
bool operator==(const Containter & another) const;
// ...
};
-
Вернуть ссылку из метода можно (в нормальной ситуации): на сам объект (
return * this;
), или на поле объекта (return this->data[i];
). Возврат ссылки или указателя на локальный объект является грубой ошибкой (для многих компиляторов это warning). (Про возврат ссылки на глобальный объект лучше не думать, т.к. в большинстве случаев глобальные объекты - признак плохого дизайна программы). -
Оператор индексирования чаще всего реализуется сразу в двух вариантых: константном и неконстантном.
class ContainerOfItems {
// ...
// Константный оператор будет использоваться, когда модификация объекта не требуется:
// cout << c[1] << endl;
const Item & operator[](int i) const;
// Неконстантный - когда происходит изменение объекта:
// c[1] = 2;
Item & operator[](int i);
// ...
};
- Переменные примитивных типов (например
int
,double
,char
), которые не должны модифицироваться при передаче в функцию/метод, должны передаваться как значения, а не как ссылки:
void setSize(int size);
Полезные опции компилятора
Компиляторы g++
и clang
поддерживают опцию -Wall
,
которая позволяет выводить все warning'и в процессе компиляции.