Существует два способа доступа к свойствам объекта:
something.bar
something['bar']
Значение между скобками может быть любым выражением. Поэтому, если имя свойства хранится в переменной, вы должны использовать нотацию в виде скобок:
var foo = 'bar';
something[foo];
// both x = something[foo] and something[foo] = x work as expected
Из стандарта:
const char c = 'c';
char* pc;
const char** pcc = &pc; // not allowed
*pcc = &c;
*pc = 'C'; // would allow to modify a const object
Здесь есть два правила:
T*
и U*
нет неявных отбрасываний, если T и U - разные типы. T*
до T const *
неявно. («указатель на T» можно отнести к «указателю на const T»). В C ++, если T
также является указателем, это правило также может быть применено к нему (цепочка). Итак, например:
char**
означает: указатель на указатель на char.
И const char**
означает: указатель на указатель на const char.
Поскольку указатель на char и указатель на const char имеют разные типы, которые не различаются только в const-ness, поэтому актерский состав не допускается. Правильный тип cast to должен быть const указателем на char.
Таким образом, чтобы оставаться const корректным, вы должны добавить ключевое слово const, начиная с самой правой звездочки.
Таким образом, char**
может быть отличным до char * const *
и также может быть добавлено к const char * const *
.
Это цепочка только C ++. В C это цепочка не работает, поэтому на этом языке вы не можете корректно наложить более одного уровня указателей const.
[h0] C ++ 11 draft standard объясняет это в примечании в разделе 4.4
, в котором говорится:
[Примечание: если программа может назначить указатель типа T ** на указатель типа const T ** (то есть, если строка 1 ниже была разрешена), программа может непреднамеренно модифицировать объект const (как это делается в строке # 2). Например,
int main() { const char c = 'c'; char* pc; const char** pcc = &pc; // #1: not allowed *pcc = &c; *pc = 'C'; // #2: modifies a const object }
-end note]
blockquote>Интересным связанным вопросом является . Если int ** p1 и const int ** p2 есть p1 = = p2 хорошо сформирован? .
Обратите внимание, что в C ++ FAQ также есть объяснение, но мне больше нравится пояснение из стандарта.
Соответствующий текст, который идет с примечанием, выглядит следующим образом:
Преобразование может добавлять cv-квалификаторы на уровнях, отличных от первого в многоуровневых указателях, с соблюдением следующих правил: 56
Два типа указателей T1 и T2 аналогичны, если существует тип T и целое число n> 0, что:
T1 является cv1,0 указателем на cv1, 1 указатель на ··· cv1, n-1 указатель на cv1, n T
blockquote>и
T2 - cv2,0 указатель на указатель cv2,1 to ··· cv2, n-1 указатель на cv2, n T
blockquote>, где каждый cvi, j является const, volatile, const volatile или ничего. N-кортеж cv-квалификаторов после первого в типе указателя, например cv1,1, cv1,2, ..., cv1, n в типе указателя T1, называется cv-квалификационной сигнатурой типа указателя , Выражение типа T1 может быть преобразовано в тип T2 тогда и только тогда, когда выполняются следующие условия:
blockquote> blockquote>
- типы указателей аналогичны.
- для каждого j> 0, если const находится в cv1, j, то const находится в cv2, j и аналогично для volatile.
- , если cv1, j и cv2, j различны, то const находится в каждом cv2, k для 0 & lt; ; k & lt; j.
Игнорируя ваш код и отвечая на принцип вашего вопроса, см. эту запись в comp.lang.c FAQ: Почему я не могу передать char ** функции, которая ожидает const char **?
Причина, по которой вы не можете присвоить значение
char **
указателюconst char **
, несколько неясна. Учитывая, что квалификаторconst
существует вообще, компилятор хотел бы помочь вам сохранить ваши обещания не изменять значенияconst
. Вот почему вы можете назначитьchar *
дляconst char *
, но не наоборот: явно безопасно «добавить»const
-ness к простому указателю, но было бы опасно его убрать. Однако предположим, что вы выполнили следующую более сложную серию заданий:const char c = 'x'; /* 1 */ char *p1; /* 2 */ const char **p2 = &p1; /* 3 */ *p2 = &c; /* 4 */ *p1 = 'X'; /* 5 */
В строке 3 мы присваиваем
blockquote>char **
const char **
. (Компилятор должен жаловаться.) В строке 4 мы присваиваемconst char *
const char *
; это явно легально. В строке 5 мы модифицируем то, что указываетchar *
- это должно быть законным. Однакоp1
заканчивается, указывая наc
, который являетсяconst
. Это произошло в строке 4, потому что*p2
был действительноp1
. Это было установлено в строке 3, которая является назначением формы, которая запрещена, и именно поэтому строка 3 запрещена.И как ваш вопрос помечен как C ++, а не C, он даже объясняет, что использовать следующие
const
квалификаторы:(C ++ имеет более сложные правила для назначения указателей со знаком const, которые позволяют вам делать больше видов назначений без каких-либо предупреждений, но все же защищать от непреднамеренных попыток изменения значений const. C ++ все же не позволил бы присвоить
blockquote>char **
const char **
, но это позволило бы вам уйти с назначениемchar **
вconst char * const *
.)
Так как никто не опубликовал решение , здесь:
char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char * const*ps = a; // no error!
( http://www.parashift.com/c++-faq-lite/ const-correctness.html # faq-18.17 для почему)