Я предполагаю, что под методом класса вы подразумеваете функцию-член. И что под «возвратом по ссылке» вы подразумеваете «вернуть ссылку на данные члена». Это в основном в отличие от возврата ссылки на local, что явно неверно.
Когда следует возвращать ссылку на данные участника, а когда сами данные?
По умолчанию вы должны возвращать сами данные (иначе «по значению»). Это позволяет избежать нескольких проблем с возвратом ссылки:
Пользователи, хранящие ссылку и становящиеся зависимыми от времени жизни ваших членов, без учета того, как долго будет жить содержащий объект (ваш объект). Приводит к висящим указателям.
Код пользователя становится зависимым от точного типа возврата . Например, вы используете vector<T>
для реализации (и это то, что возвращает ваш геттер). Появляется код пользователя типа "vector<T> foo = obj.getItems()
". Затем вы изменяете свою реализацию (и получатель), чтобы использовать deque<T>
- разрывы кода пользователя. Если бы вы возвращали по значению, вы могли бы просто заставить получателя создать локальный вектор, скопировать данные из deque члена и вернуть результат. Вполне разумно для небольших коллекций. [*]
Так когда же вы должны вернуть ссылку?
- Вы можете рассмотреть это, когда возвращаемый объект огромен (
Image
) или не подлежит копированию (boost::signal
). Но, как всегда, вы можете вместо этого выбрать более ООП-модель, в которой ваш класс делать , а не иметь материал , свисающий с него . В случае Image
вы можете предоставить функцию-член drawCircle
вместо возврата Image&
и для того, чтобы ваши пользователи нарисовали на ней кружок.
- Когда ваши данные логически принадлежат вашему пользователю, а вы просто держите их для него. Рассмотрим коллекции std:
vector<T>::operator[]
возвращает ссылку на T, потому что это то, что я хочу получить: мой точный объект, а не его копия.
[*] Существует лучший способ обеспечить код на будущее. Вместо того, чтобы возвращать вектор (по ref по значению), верните в ваш вектор пару итераторов - начальный и конечный. Это позволяет вашим пользователям делать все , что они обычно делают с deque или вектором, но независимо от фактической реализации. Boost предоставляет boost::iterator_pair
для этой цели. Как перк, он также перегружен оператором [], так что вы даже можете сделать «int i = obj.getItems()[5]
» вместо «int i = obj.getItems().begin()[5]
».
Это решение применимо к любой ситуации, которая позволяет обрабатывать типы в общем. Например, если у вас есть Dog
член, но ваши пользователи должны знать только, что это Animal
(потому что они только вызывают eat()
и sleep()
), верните ссылку Animal / указатель на бесплатная копия вашей собаки. Затем, когда вы решите, что собаки слабые, и вам действительно нужен волк для реализации, код пользователя не сломается.
Этот вид сокрытия информации делает больше, чем просто обеспечивает совместимость в будущем. Это также помогает сохранить ваш дизайн в чистоте.