Перегрузка с помощью "const" в конце объявления функции
У меня есть 3 попытки перегрузить функцию "begin()"
class Test
{
public:
//case 1: compiler error
int begin();
const int begin();
//case 2:compiler warning: type qualifiers ignored on function return type
int begin();
const int begin() const;
//case 3: ok
int begin();
int begin() const;
};
Для двух успешных сборок, как компилятор выбирает, какая перегрузка вызывается begin()
?
3 ответа
Функции-члены имеют неявный аргумент, который является экземпляром самого класса. Таким образом, вы можете думать, что ваши функции действительно выглядят так:
// 1) compile-error as const-qualifications on return doesn't distinguish
// the functions - you cannot overload on return type
int begin(Test& );
const int begin(Test& );
// 2)
int begin(Test& );
const int begin(const Test& );
// 3)
int begin(Test& );
int begin(const Test& );
Во втором и третьем случаях const
-квалификация функции эквивалентна тому, что неявный аргумент является ссылкой на const. Поэтому, когда у вас есть что-то вроде:
Test{}.begin();
Что вызывает begin()
используя ссылку на неконстантный Test
в качестве неявного первого аргумента. Обе перегрузки begin()
жизнеспособны, оба не требуют преобразований, поэтому предпочтительна наименее квалифицированная cv ссылка, а именноconst
квалифицированная функция.
Вместо этого, когда у вас есть:
(const Test{}).begin();
мы звоним begin()
со ссылкой на const Test
, Так что неconst
-qualified функция не является жизнеспособным кандидатом (вы не можете передать const-ref функции, ожидающей не-const-ref), поэтому лучший жизнеспособный кандидат - единственный жизнеспособный кандидат: int begin() const
,
Случай 1 является неоднозначным, потому что возвращаемый тип не участвует в разрешении перегрузки, случай 2 эквивалентен случаю 3, потому что const отбрасывается в возвращаемом типе. В случае 3:
const Test t1;
t1.begin() // calls int begin() const;
Test t2;
t2.begin() // calls int begin();
Нестатическая функция-член может быть объявлена с квалификатором const, volatile или const volatile (этот квалификатор появляется после имени функции в объявлении функции). По-разному cv-квалифицированные функции имеют разные типы и поэтому могут перегружать друг друга. В теле cv-квалифицированной функции этот указатель является cv-квалифицированным, например, в функции-члене const, только другие функции-члены const могут быть вызваны нормально. (Неконстантная функция-член может все еще вызываться, если применяется const_cast или через путь доступа, который не включает это.)
Несколько правил, которые нужно запомнить:
Вы не можете перегружать методы, основываясь только на типе возвращаемого значения. Это приводит к ошибке в вашем случае 1.
При возврате по значению квалификатор const является избыточным. В вашем случае 2, компилятор предупреждает вас об этом.
Каждый нестатический метод класса имеет неявный аргумент. При вызове метода это присваивается экземпляру, для которого вызывается метод. К этому неявному аргументу применяется ключевое слово const в конце объявления метода (перед телом метода). По сути, вы говорите, что тело функции не будет изменять состояние (члены данных) экземпляра. Если вы вызываете метод для экземпляра const, вам необходимо определить метод const. Кроме того, вы можете перегружать метод исключительно на основании того, является ли он постоянным или нет.