Поведение перегрузки функций с помощью const
Я работаю над g ++ и здесь я попытался перегрузить функцию, просто добавив const
к параметру. Работает нормально и при запуске вызывает функцию без const
- Это поведение указано в стандарте C++?
По какой причине она вызывает функцию без
const
void print(const std::string& str){std::cout << "const" << str << std::endl;} void print(std::string& str){std::cout << str << std::endl;} int main() { std::string temp = "hello"; print(temp); return 0; }
6 ответов
Ссылочные привязки являются категорией идентичности §13.3.3.1.4), но поскольку последняя более cv-квалифицирована, для §13.3.3.2 предпочтение отдается неконстантным (пример кода из стандарта):
int f(const int &);
int f(int &);
int i;
int j = f(i); // calls f(int &)
Это стандартное поведение. Любое другое поведение приведет к сумасшедшему поведению. В частности, неконстантная функция вообще не будет вызываться.
Перегрузка работает путем сопоставления типов аргументов, включая квалификаторы. В твоем случае temp
имеет тип std::string
не const std::string
, Вы только инициализировали его литеральной константой, она сама по себе не является константой.
Учтите следующее:
std::string temp( "hello" ) ;
print(temp); // hello
print( std::string("hello") ) ; // consthello
print( "hello" ) ; // consthello
print( static_cast<const std::string>(temp) ) ; // consthello
const std::string temp2( "hello" ) ;
print(temp2); // consthello
Если вы удалите неконстантную версию, все три вызовут оставшуюся константную перегрузку. В этом примере только константная версия фактически необходима (и предпочтительна), поскольку ни одна из версий не изменяет строковый объект.
С другой стороны, если вы удалили неконстантную версию, не было бы ни одной функции, соответствующей какому, кроме первого примера выше, и сборка не удалась бы. То есть неконстантный объект может быть безопасно передан как аргумент const, но константный объект не может быть передан как неконстантный аргумент, потому что функция не "обещает" не изменять объект. Вы можете заставить const в неконстантный аргумент const_cast
как в:
const std::string temp2("hello") ;
print( const_cast<std::string&>(temp2) ) ; // hello
Но если print()
Были попытки изменить объект, в этом случае результаты не определены, поэтому считают практику небезопасной.
Создание аргумента const указывает на намерение, позволяет компилятору выдавать диагностику, если код пытается изменить объект или передать его через неконстантный аргумент какой-либо другой функции. Это также может потенциально предоставить компилятору возможности оптимизации.
Причина в этом разделе в [over.ics.rank]/3, где этот случай явно рассматривается:
Стандартная последовательность преобразования
S1
является лучшей последовательностью преобразования, чем стандартная последовательность преобразованияS2
если
[...]
-S1
а такжеS2
являются привязками ссылок (8.5.3), и типы, на которые ссылаются ссылки, относятся к одному и тому же типу, за исключением cv-квалификаторов верхнего уровня, и типа, к которому ссылка инициализируетсяS2
ссылка более квалифицирована по cv, чем тип, к которому ссылка инициализированаS1
относится.
S1
соответствует второй перегрузке и S2
к первому.
По какой причине она вызывает функцию без
const
Вы всегда стараетесь выбрать наиболее специализированную вещь. Это относится к разрешению перегрузки так же, как и к частичному упорядочению шаблонов функций. Вторая перегрузка является более специализированной, чем первая, потому что первая может вызываться с аргументами, с которыми вторая не может быть вызвана - это основная причина, лежащая в основе этого правила.
const является частью сигнатуры метода. Переопределение работает только для методов с одинаковой сигнатурой. Это поведение было сделано, чтобы избежать обратной ситуации, когда вы используете метод const базового класса для вызова неконстантного метода дочернего класса.
Потому что вызов функции принимает std::string const&
требует двух неявных преобразований: один в std::string const
, один к std::string const&
; тогда как вызов функции std::string&
требуется только одно неявное преобразование std::string&
), так что один является предпочтительным.