Как уже упоминалось в разделе 2.3.3, проще всего понять эти объявления, читая их справа налево. В данном случае ближе всего к имени curErr расположен спецификатор const, означая, что сам объект curErr будет константным. Тип этого объекта формирует остальная часть оператора объявления. Следующий символ оператора объявления, *, означает, что curErr — это константный указатель. И наконец, объявление завершает базовый тип, означая, что curErr — это константный указатель на объект типа int. Аналогично pip — это константный указатель на объект типа const double.

Тот факт, что указатель сам является константой, ничто не говорит о том, можем ли мы использовать указатель для изменения основного объекта. Возможность изменения объекта полностью зависит от типа, на который указывает указатель. Например, pip — это константный указатель на константу. Ни значение объекта, на который указывает указатель pip, ни хранящийся в нем адрес не могут быть изменены. С другой стороны, указатель curErr имеет простой, неконстантный тип int. Указатель curErr можно использовать для изменения значения переменной errNumb:

*pip = 2.72; // ошибка: pip - указатель на константу

// если значение объекта, на который указывает указатель curErr

// (т.е. errNumb), отлично от нуля

if (*curErr) {

 errorHandler();

 *curErr = 0; // обнулить значение объекта, на который

              // указывает указатель curErr

}

Упражнения раздела 2.4.2

Упражнение 2.27. Какие из следующих инициализаций допустимы? Объясните почему.

(a) int i = -1, &r = 0;       (b) int *const p2 = &i2

(c) const int i = -1, &r = 0; (d) const int *const p3 = &i2

(e) const int *p1 = &i2      (f) const int &const r2;

(g) const int i2 = i, &r = i;

Упражнение 2.28. Объясните следующие определения. Какие из них недопустимы?

(a) int i, *const cp;      (b) int *p1, *const p2;

(c) const int ic, &r = ic; (d) const int *const p3;

(e) const int *p;

Упражнение 2.29. С учетом переменных из предыдущих упражнений, какие из следующих присвоений допустимы? Объясните почему.

(a) i = ic;   (b) pi = p3;

(с) pi = ⁣ (d) p3 = ⁣

(e) p2 = pi;  (f) ic = *p3;

<p><image l:href="#reader.png"/>2.4.3. Спецификатор <code>const</code> верхнего уровня</p>

Как уже упоминалось, указатель — это объект, способный указывать на другой объект. В результате можно сразу сказать, является ли указатель сам константой и являются ли константой объекты, на которые он может указывать. Термин спецификатор const верхнего уровня (top-level const) используется для обозначения того ключевого слова const, которое объявляет константой сам указатель. Когда указатель способен указывать на константный объект, это называется спецификатор const нижнего уровня (low-level const). 

В более общем смысле спецификатор const верхнего уровня означает, что объект сам константа. Спецификатор const верхнего уровня может присутствовать в любом типе объекта, будь то один из встроенных арифметических типов, тип класса или ссылочный тип. Спецификатор const нижнего уровня присутствует в базовом типе составных типов, таких как указатели или ссылки. Обратите внимание, что ссылочные типы, в отличие от большинства других типов, способны иметь спецификаторы const как верхнего, так и нижнего уровня, независимо друг от друга.

int i = 0;

int *const pi = &i  // нельзя изменить значение pi;

                     // const верхнего уровня

const int ci = 42;   // нельзя изменить ci; const верхнего уровня

const int *p2 = &ci // нельзя изменить p2; const нижнего уровня

const int *const p3 = p2; // справа const верхнего уровня, слева нет

const int &r = ci;   // const в ссылочных типах всегда нижнего уровня

Различие между спецификаторами const верхнего и нижнего уровней проявляется при копировании объекта. При копировании объекта спецификатор const верхнего уровня игнорируется.

i = ci;  // ok: копирование значения ci; спецификатор const верхнего

Перейти на страницу:

Похожие книги