2013-09-23 3 views
1

Мне просто интересно, я хочу знать, что происходит здесь:C++ символ * инициализация в конструкторе

class Test 
{ 
char * name; 
public: 
Test(char * c) : name(c){} 
}; 

1) Почему не Test(const char * c) : name(c){} работы? Потому что char * name не const? Но что об этом:

main(){ 
char * name = "Peter"; 
} 

name это символ *, но "Peter" является Const символ *, верно? Как работает эта инициализация?

2) Test(char * c) : name(c){ c[0] = 'a'; } - это сбой программы. Зачем?

Извините за мое невежество.

+1

Что значит 'name (c)' не работает? Определите «работы». –

+0

@Eitan недействительное преобразование из const char * в char * – tuks

+0

'' Peter '' is 'const char [6]', а не 'const char *'. – chris

ответ

5

Почему не будет Test(const char * c) : name(c) {}? Потому что char * name не const?

Исправить.

как делает эту инициализацию работу: char * name = "Peter";

A C строка ++ литерал типа char const[] (см here, в отличие от просто char[] в C, так как он не имел const ключевое слово). Это задание считается устаревшим в C++, но он по-прежнему разрешено для обратной совместимости с С.

Test(char * c) : name(c) { c[0] = 'a'; } сбой программы. Зачем?

Что вы передаете в Test при инициализации? Если вы передаете строковый литерал или нелегальный указатель, делать c[0] = 'a' не допускается.


старая версия языка программирования С (как описано в книге R K &, опубликованной в 1978 году) не включают const ключевое слово. С тех пор ANSI C заимствовал идею const из C++.
Действителен в C++ 03, более не действителен в C++ 11.

+0

'char * c =" hello "; Тест t (c); 'или просто' Test t («hello»); 'оба сбой – tuks

+1

@tuks. Они лучше сбой! Строковый литерал «привет» не может быть изменен, и вы пытаетесь перезаписать свой первый байт на «a». –

+0

В C есть _is_ ключевое слово 'const', и всегда было AFAIK (это, безусловно, в C89, и все еще в C11.) –

-2

1а) Право

1b) "Peter" не const char*, его это char*, но он не может быть изменен. Причина в том, что совместимость со временем до const существовала на этом языке. Много кода уже существовало, что сказал char* p = "fred";, и они не могли просто сделать этот код незаконным в одночасье.

2) Не могу сказать, почему это приведет к сбою программы, не видя, как вы используете этот конструктор.

+0

Неправильно. Кто это поддержал? '" Peter "' является 'char const [6]', а не 'char *'. –

+0

@ KonradRudolph, если это 'char const [6]', то как это называется 'char * name =" Peter ",' legal? – john

+0

1) как это происходит: 'Test (const char * c) {name = new char [strlen (c) +1]; strcpy (name, c);} 'если я пишу' Test t («Peter»); ', конструктор ожидает const char *, но' 'Peter '' is char *? 2) Тест t («Привет»); – tuks

2

Прежде всего, это C++, у вас есть std::string.Вы действительно должны использовать его.

Что касается вашего вопроса, то "Peter" является символом символа, следовательно, он не поддается изменению и, конечно же, вы не можете писать на нем. Вы можете:

  • имеет переменный с const char * членом и инициализировать его, как вы делаете name(c), объявляя "Peter", как const
  • имеет переменный в char * члене и скопировать содержимое, например name(strdup(c)) (и не забудьте выпустить его в деструктор.
0
  1. Correct.

  2. «Питер» обычно хранится в ячейке памяти только для чтения (фактически, это зависит от того, на каком устройстве мы находимся), потому что это строковый литерал. Не определено, что происходит, когда вы пытаетесь изменить строковый литерал (но вы, вероятно, можете догадаться, что не должны).

В любом случае вы должны использовать std::string.

3

Переход на const является, так сказать, улицей с односторонним движением.

Вы можете конвертировать из T * в T const * неявно.

Преобразование из T const * в T * требует явного приведения. Даже если вы начали с T *, а затем преобразованы в T const *, конвертация назад в T * требует явного приведения, хотя это действительно просто «восстановление» доступа, с которым вы должны были начать.

Обратите внимание, что во всем, T const * и const T * в точности эквивалентны, и T означает «некоторого произвольного типа» (char в вашем примере, но может так же легко быть что-то еще, как int или my_user_defined_type).

char * Инициализации из строкового литерала (например, char *s = "whatever";) допускаются, даже если он нарушает это общее правило (в буквальном смысле сам по себе является в основном const, но вы создаете неконстантный указатель на него). Это просто потому, что от этого зависит много кода, и никто не хотел нарушать этот код, поэтому у них есть правило, позволяющее это делать. Однако это правило было устаревшим, поэтому, по крайней мере теоретически, какой-то будущий компилятор мог бы отбросить код, который зависит от него.

Поскольку строковый литерал в основном является const, любая попытка его изменения приводит к неопределенному поведению. В большинстве современных систем это приведет к завершению процесса, поскольку память, хранящая строковый литерал, будет отмечена как «только для чтения». Это не единственный возможный результат. Например, еще во времена MS-DOS это часто бывает успешным. Тем не менее, он все еще может иметь причудливые побочные эффекты. Например, многие компиляторы «знали», что строковые литералы должны быть доступны только для чтения, поэтому они «сливают» идентичные строковые литералы.Поэтому, если у вас что-то вроде:

char *a = "Peter"; a[1] = 'a'; 

char *b = "Peter"; 

cout << b; 

Компилятор будет иметь «слиты» a и b на самом деле указывают на ту же память, - так что, когда вы изменили a, что изменения будут также влиять на b, поэтому он будет печатать «Патер» вместо «Петра».

Обратите внимание, что строковые литералы не обязательно должны быть полностью идентичными для этого. Пока один был идентичен концу другой, они могут быть объединены:

char *a = "this?"; 
char *b = "What's this?"; 

a[2] = 'a'; 
a[3] = 't'; 

cout << b; // could print "What's that?" 

Мандаты одно поведения не имел смысла, так что результат был (и есть) просто не определен.

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