Перегрузка функции const
Я запутался, почему следующий код не выдает никакой ошибки, потому что переданные для отображения аргументы имеют тот же тип, т.е. char
.Does const
действительно имеет значение?
#include<iostream>
using namespace std;
void display(char *p)
{
cout<<p;
}
void display(const char *p)
{
cout<<p;
}
int main()
{
display("Hello");
display("World");
}
РЕДАКТИРОВАТЬ Согласно ответам, первый дисплей никогда не вызывается, который является правильным, и вывод тоже.
Но предположим, что я делаю это так:
int main()
{
char *p="Hello";
display(p);//now first display is called.
display("World");
}
Компилятор дает warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
но затем он вызывает first display. Означает ли это, что строка больше не воспринимается как константа?
6 ответов
const char*
а также char *
на самом деле не то же самое. Позже можно изменить указанную char
в то время как первый предотвратит это.
Также обратите внимание, что если бы это были методы класса, void display()
а также void display() const
также будут допустимы перегрузки. Последнее подразумевает, что метод не должен изменять состояние объекта.
Рассмотрим этот код:
void display(char *s)
{
std::cout << "Display" << std::endl;
}
void display(const char *s)
{
std::cout << "Display with const" << std::endl;
}
int main()
{
char *str = strdup("boap");
const char *str2 = "toto";
/* It is a string literral "bound" as a char *.
Compiler will issue warning, but it still compiles.
Avoid to do that, it's just an exemple */
char *not_safe = "not_safe";
display("llama");
display(str2);
display(str);
display(not_safe);
}
Это напечатает Display with const
дважды, а затем дважды Display
, Смотрите там. Теперь посмотрим, почему:
"llama"
является строковым литералом, а затем разрешается какconst char *
,str2
указатель на строковый литерал Поскольку его типconst char*
это также касаетсяconst
перегрузки.not_safe
также указатель на строковый литерал. Тем не менее, его типchar *
Это не правильно. Память, на которую он указывает, доступна только для чтения, и попытка ее изменения приведет к сбою. Тем не менее, тип переменной по-прежнемуchar *
так что это решимость неconst
перегрузки.str
этоchar *
указатель и строка, на которую он указывает, не доступны только для чтения. Изменение его содержимого допустимо, и так как его типchar *
, это разрешит к неконстантной перегрузке.
Проблема в том, что строковые литералы, такие как "Hello"
а также "World"
иметь тип const char[6]
, Это может распасться на const char*
, но не для char*
, Таким образом, перегрузка const char*
,
void display(const char *p);
это лучший матч. Как указывает @JamesKanze, было бы возможно, чтобы функция char*
принять строковый литерал, но попытка изменить данные, на которые указывают, приведет к неопределенному поведению. По этой причине небезопасно передавать строковые литералы таким функциям. С подходящими настройками предупреждений GCC производит следующее:
предупреждение: устаревшее преобразование из строковой константы в 'char*'
В любом случае, при наличии двух перегрузок, подобных тем, которые вы показали, const char*
выигрывает.
Аргументы, передаваемые двум функциям, на самом деле не совпадают.
Первый занимает char*
: Указатель на char
,
Второй занимает const char*
: Указатель на const char
,
Итак, вы видите, разница здесь на самом деле в том, указывает ли указатель на объект, который можно изменить или нет. Это определенно свойство, для которого вы хотите иметь возможность перегружать функцию.
Размеры строк "Hello" и "World" известны во время компиляции и не могут быть изменены. Это постоянные массивы символов времени компиляции.
В C и C++, массив, например char a[6]
можно ссылаться с помощью указателя, т.е. a
на самом деле char *
, Поскольку массивы для "Hello" и "World" не должны быть изменены во время выполнения, их тип по существу const char *
,
Компилятор распознает это и выполняет разрешение перегрузки для display
правильно, так как только одна из функций (display(const char* p)
) занимает const char*
в качестве аргумента. Вот почему в этих двух функциях нет двусмысленности, и вы не получите ошибку, которую ожидали получить.
Можете ли вы изменить объект или нет, это полезная информация, в зависимости от которой вы можете вызывать другое поведение! Учти это:
void foo(int * p) { ++(*p); }
void foo(int const * p) { std::cout << *p << '\n'; }
msgstr "потому что аргументы, передаваемые для отображения, имеют один и тот же тип, т.е.
Нет здесь аргумент "const char*". тип данных является тем, но квалификатор const указывает, что литеральная строка, которую вы жестко закодировали, не может быть изменена.
"Const действительно имеет значение?"
Да, const определитель имеет значение. в Display(char*) вы можете обновить содержимое строки с нулевым символом в конце, которую вы передали, но не в Display(const char*). Этот факт позволяет больше оптимизации компилятором.
Но прочитайте, что http://www.possibility.com/Cpp/const.html это хороший источник, чтобы начать эффективно использовать const.