2014-11-08 2 views
1

Это то, что всегда заинтриговало меня языком C++. С появлением идентификатора «const» он должен был заменить использование оператора #define для объявления констант. Но, как я уже сказал, чтобы использовать их, я оказался в const char для безумия конверсии ошибок.Почему «const int» используется для преобразования «int», но «const char []» в «char *» не

В последнее время я заявлял, что делаю это в константах класса, как в Java. Поэтому я решил объявить что-то вроде этого.

private: const static int NB_FIELD = 22; 

Это прекрасно работает. Функция, возвращающая int, может возвращать «const int» без каких-либо проблем.

Но теперь, если я пытаюсь сделать то же самое со строкой, как это:

private: static const char ERRORSTR [ 6 ]; 

Какого constains строка «Error», он будет генерировать константный символ СИМВОЛА проблемы преобразования, как в этой функции.

char* EnhancedSQLobject::get_SQLname (int index) 
{ 
    if (index < p_nb_field && index >= 0) 
     return (p_SQLfield_ptr [ index ] . SQLname) 

    return (ERRORSTR); 

} 

Теперь некоторые люди говорят, изменить возвращаемое значение для сопзЬ символ *, но я не могу, потому что если индекс действителен, он вернет неконстантную переменный, но если индекс является недействительным, то это будет верните строку с постоянной ошибкой.

Таким образом, мой выбор состоит в том, чтобы сделать строку ошибки непостоянной или создать константу с помощью операторов #define. Я давно помню попытку определить все как const char, но в конце концов он взорвался где-то еще в цепочках конверсии. Просто упростить использование регулярного символа (класс String для меня не вариант)

Это просто смешно, зачем использовать функцию, которая работает только для части переменных. Я предполагаю, что это связано с тем, что укусы на самом деле являются таблицей символов, поэтому он, вероятно, возвращает указатель вместо значения.

+1

«Это просто смешно, зачем применять функцию, которая работает только для части переменных типов». - На самом деле, это не то, что происходит. В одном случае вы говорите о том, что 'const int' соответствует' int', но в другом случае вы говорите о 'const char *' в 'char *', в котором добавлен уровень косвенности. –

+0

Вы сравниваете тип non-pointer-type с типом указателя.'T' нельзя сравнивать с' T2 * ', предполагая, что' T' и 'T2' являются базовыми типами. – Ajay

+0

В одном случае копируется 'int'. В другом, указатель скопирован, и поскольку он указывает на постоянные данные, почему будет работать преобразование? – chris

ответ

0

Существует разница между двумя преобразованиями. Для int:

const int ci = 7; 
int i = ci; // fine... 
++i;  // ... because ci is still 7 

Но если вы могли бы сделать это для char*:

const char msg[] = "Hi"; 
char* p = msg; // not OK... 
*p = 'B';  // ... because now msg = "Bi" 
       //  and it was supposed to be const! 

Фактический эквивалент бывший для указателей будет:

char * const cc = someBuf(); 
char * c = cc; // this is totally OK 
++c;   // ... because we're not modifying cc in any way 

Это разница между константной указатель и указатель на const.

2

В одном случае вы говорите о литье const int в int, а в другом вы отливаете const char* в char*. На самом деле это разные ситуации, которые должны вести себя по-другому, потому что последний имеет добавленный уровень косвенности (указатель). Вы абсолютно можете наложить const char на char, но это не то, что вы делаете.

Рассмотрим следующий ошибочный код:

const int i = 50; 
int j = i; 
int* p = &i; // ERROR 

Я пытаюсь сделать int j = i; и что это хорошо. Исходный объект i остается const, а объекту j присваивается то же значение, что и i.Однако, если я попытаюсь сделать int* p = &i;, у нас есть проблема. Если бы это было скомпилировано, у нас было бы p, указывающее на константу int, хотя она сообщает нам, что она указывает на неконстантный int. Это позволило бы нам изменить объект const i с помощью указателя p - это очень плохо.

У вас такая же ситуация здесь, только с char s. Все char s в вашем ERRORSTR: const. Затем вы не можете вернуть char*, который указывает на любой из этих char s, потому что это будет ложь. Указатель не указывает на неконстантный char, но на char const.

int s и char s не ведут себя по-другому в этом отношении.

Однако, я думаю, вы только вошли в это затруднительное положение из-за плохого дизайна интерфейса. Почему ваша функция возвращает специальную строку, когда она не может найти «имя SQL» (что бы это ни было)? Что, если, например, строка «Ошибка» была фактически допустимым именем? Как бы вызывающая функция описала разницу? Я бы сказал, что если ваша функция не в состоянии выполнить действие get_SQLname (то есть, оно не может получить имя), оно должно вызвать исключение.

Кроме того, вы должны использовать std::string вместо C-стиля char* s.

+0

«Что, если, например, строка« Ошибка »действительно была действительным именем?» - В действительности эта строка не интерпретируется компьютером. просто я вижу эту строку на экране или в базе данных, тогда я знаю, что произошла ошибка. – larienna

+0

«Кроме того, вы должны использовать std :: string вместо C-style char * s." - Я ничего не имею против класса string в Java, но на C++ я стараюсь избегать этого, так как у меня так много проблем с ним. На самом деле, я даже не использую динамическое распределение, если я действительно не нуждаюсь в нем. Спасите меня много проблем и ошибок, которых трудно найти. Снова в Java, я бы не прочь. – larienna

+0

@larienna Да? С какими проблемами вы сталкиваетесь с 'std :: string'? Вы не должны выполнять ручное динамическое распределение с помощью 'std :: string' вообще. –

0

Только так вы знаете, с помощью #define не будет работать, как вы ожидаете, что будет, по крайней мере, если вы действительно используете C++, а не С.

В C++, Строковый литерал const, таким образом, если вы заявляете:

#define ERRORSTR "ERROR" 

И вы пытаетесь return ERRORSTR от get_SQLname, это может привести к непредсказуемому поведению, если вы пытаетесь изменить возвращенную строку. Весьма вероятно, что ваш компилятор только выдает предупреждение для этого, потому что этот факт, что строковые литералы const не всегда был истинным в C++ давным-давно.

#include <iostream> 

#define BLAH "blah" 

char *foo() { 
    return BLAH; 
} 

int main(int argc, char *argv[]) { 
    std::cout << foo() << std::endl; 
} 

На мой компилятор, я вижу следующее предупреждение:

so.cpp:6:12: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings] 

реальность такова, что использование #define для констант, особенно строковые константы небезопасно именно по этой причине, и, таким образом, следует избегать. const предоставляет вам некоторый уровень безопасности компилятором, и если компилятор говорит вам, что преобразование небезопасно, есть причина для этой ошибки, и вы должны попытаться выяснить, что это за причина, и решить проблему вместо просто пытаясь заставить замолчать ошибку или найти какое-то другое обходное решение. Фактически, полагаясь на поведение с C, как правило, это запах кода на C++, и полагаться на семантику другого языка, такого как Java, еще хуже. Несмотря на их сходство в синтаксисе, Java, C и C++ все очень отличаются друг от друга в своей фактической семантике. Было бы лучше, если бы вы узнали эти различия, а не просто пытались применить знания, которые вы знаете, с одного языка на другой.

Смежные вопросы