Перегрузка функции 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.

Другие вопросы по тегам