Почему объявление функции с аргументом const допускает вызов функции с аргументом non-const?
Обратите внимание на следующий код С++:
#include <iostream>
using std::cout;
int foo (const int);
int main ()
{
cout << foo(3);
}
int foo (int a)
{
a++;
return a;
}
Обратите внимание, что прототип foo()
принимает значение const int
и что определение принимает int
. Эта компиляция без ошибок...
Почему нет ошибок компиляции?
Ответы
Ответ 1
Поскольку для вызывающего объекта foo
не имеет значения, изменяет ли foo
свою копию переменной или нет.
В частности, в стандарте С++ 03 следующие два фрагмента объясняют, почему:
С++ 03 Раздел: 13.2-1
Две объявления функций с тем же именем относятся к одной и той же функции, если они находятся в одной области и имеют эквивалентные объявления параметров (13.1).
С++ 03 Раздел: 13.1-3
Объявления параметров, которые отличаются только наличием или отсутствием константы и/или летучих, эквивалентны. В этом случае игнорируются только константы-константы const и volatile на самом внешнем уровне спецификации типа параметра; const и volatile-спецификаторы, скрытые в спецификации типа параметра, являются значительными и могут использоваться для различения перегруженных деклараций функций.
Ответ 2
Верхний уровень const
(т.е. применимый к переданному значению, а не к тому, на что он указывает или ссылается) влияет только на реализацию, а не на интерфейс, функции. Компилятор игнорирует его с точки зрения интерфейса (т.е. Вызывающей стороны) и применяет его только к реализации (т.е. Код в теле функции).
Ответ 3
Как объяснили другие, стандарт говорит, что это нормально, и что компилятор может позволить себе проявлять снисходительность к обеспечению этого, потому что он не влияет на вызывающего, но никто не ответил, почему компилятор должен быть мягким. Это не особенно мягко в целом, и программист, который просто смотрел на интерфейс, затем погружается в реализацию, может иметь это в глубине своего сознания, что параметр const, когда он нет, или наоборот - не очень хорошо.
Эта снисходительность позволяет изменять реализацию без изменения заголовков, которые с использованием традиционных инструментов делают триггеры перекомпиляции клиентского кода. Это может быть серьезной проблемой в развитии масштаба предприятия, где существенное изменение в заголовке низкого уровня (например, ведение журнала) может привести к перестройке практически всех объектов между ним и приложениями... тратить тысячи часов на процессорное время и задерживая всех и вся, ожидающих сборки.
Итак, это уродливо, но практическая уступка.
Я также ответил на другой аналогичный вопрос, который рассматривает, почему недогрузка f (const T) и f (T) не допускается - может представлять интерес для всех, кто это читает - Верхний уровень const не влияет на подпись функции
Ответ 4
int foo (const int a)
{
a++;
return a;
}
Это приведет к ошибке при компиляции.