Вопрос касается перегрузки operator[]
, а именно различия в создании константной и неконстантной версии. В большинстве случаев это будет выглядеть так:
T& operator[](size_t i);
const T& operator[](size_t i) const;
У меня есть несколько теоретических вопросов. Практически всегда сам вызов operator[]
не модифицирует объект, а значит даже неконстантную версию стоило бы объявить как const-метод.
Первый вопрос: правильно ли я понимаю, что мы не объявляем его const-методом только потому, что хотим, чтобы эти методы не конфликтовали, и чтобы при обращении к элементу некоторого константного класса вызывался второй вариант перегруженного оператора?
Второй вопрос: верно ли, что если объект будет неконстантный, для него при вызове operator[]
всегда будет вызываться первая перегруженная версия?
"неконстантную версию стоило бы объявить как const-метод"
Вы пробовали? Ведь если ваш объект - константный, как вы сможете вернуть неконстантную ссылку на константный объект?
Грубо -
class Test
{
int& operator[](int i) const { return data[i]; }
private:
int data[10];
};
Ведь в этом случае data
тоже становится константным.
Если бы это было возможно - тем самым была бы дыра, позволяющая законно изменять константный объект...
Практически всегда сам вызов operator[]
не модифицирует объект
Зависит от семантики. Например, std::map
, std::unordered_map
вообще не имеют const
версий этого оператора, по той причине, что вызов с несуществующим ранее ключом приводит к созданию нового элемента в контейнере (явное изменение объекта).
Пара, описанных в вопросе сигнатур (с некоторыми нюансами) используется в стандартной библиотеке для std::basic_string
, std::vector
, std::deque
, std::bitset
, std::array
, std::valarray
. Т.е. константная версия возвращает константную ссылку (кроме bitset
, он возвращает bool
по значению), а неконстантная, соответственно, обычную ссылку на элемент контейнера. У std::valarray
, кстати, есть несколько пар перегрузок с разными типами параметров, но это уже другая история.
Есть и типы, имеющие только константную версию оператора. Это std::basic_string_view
, std::reverse_iterator
, std::move_iterator
и std::match_results
. Отсутствие обычной версии обусловлено необходимость доступа только-для-чтения к членам-данным объекта.
Но есть и более необычные ситуации, например, для std::unique_ptr
и std::shared_ptr
, когда они владеют массивами объектов. Например, в std::unique_ptr
объявлена такая сигнатура:
T& operator[](size_t i) const;
Т.е. функция константная (не меняет своих членов-данных), но при этом возвращает неконстантую ссылку на объект, которым управляет указатель, и т.о. этот объект может быть изменен. Иначе бы просто сама концепция "умных" указателей была бы не так полезна.
мы не объявляем его const-методом только потому, что хотим, чтобы эти методы не конфликтовали
В частности, да. Это ограничение механизма перегрузки. Если функция останется константной, то она должна будет принимать уже какой-то другой тип в качестве параметра. Т.к. по возвращаемым типам перегрузка не работает. Но и из-за иной ситуации, уже описанной в другом ответе, когда функция константа, то и все члены-данные объекта this
в этой функции константы. Чтобы можно было вернуть что-то неконстантное в этом ситуации, надо возвращать либо копию по значению, либо добавлять косвенности, как это сделано в "умных" указателях. Ведь указатель, который нельзя менять не запрещает менять данные, расположенные по адресу, хранимом в указателе.
верно ли, что если объект будет неконстантный, для него при вызове operator[] всегда будет вызываться первая перегруженная версия?
Верно, но ничто не мешает сделать const_cast
приведение, добавляющее const
. Можно явно, а можно и через передачу в функцию, принимающую константную ссылку. В обратную же сторону (снятие const
) приведение стоит делать с большей осторожностью.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
При попытке вывести ip, вместо заданного выводятся непонятные цифры
Есть прокси-сервер, написанный на асинхронном API BoostAsio - async_* функции и коллбеки
Решил реализовать на своём сайте поисковикСделал через ajax в js
Изменяю размер окна браузера, шапка двигаетсяКак сделать, чтобы заголовок не перемещался?