Выбрать главу

double *ptr = minWage;

Должен ли компилятор разрешить подобное присваивание? Поскольку minWage – константа, ей нельзя присвоить значение. С другой стороны, ничто не запрещает нам написать:

*ptr += 1.40; // изменение объекта minWage!

Как правило, компилятор не в состоянии уберечь от использования указателей и не сможет сигнализировать об ошибке в случае подобного их употребления. Для этого требуется слишком глубокий анализ логики программы. Поэтому компилятор просто запрещает присваивание адресов констант обычным указателям.

Что же, мы лишены возможности использовать указатели на константы? Нет. Для этого существуют указатели, объявленные со спецификатором const:

const double *cptr;

где cptr – указатель на объект типа const double. Тонкость заключается в том, что сам указатель – не константа, а значит, мы можем изменять его значение. Например:

const double *pc = 0;

const double minWage = 9.60;

// правильно: не можем изменять minWage с помощью pc

pc = minWage;

double dval = 3.14;

// правильно: не можем изменять minWage с помощью pc

// хотя dval и не константа

pc = dval; // правильно

dval = 3.14159; //правильно

*pc = 3.14159; // ошибка

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

pc = dval;

Константный указатель не позволяет изменять адресуемый им объект с помощью косвенной адресации. Хотя dval в примере выше и не является константой, компилятор не допустит изменения переменной dval через pc. (Опять-таки потому, что он не в состоянии определить, адрес какого объекта может содержать указатель в произвольный момент выполнения программы.)

В реальных программах указатели на константы чаще всего употребляются как формальные параметры функций. Их использование дает гарантию, что объект, переданный в функцию в качестве фактического аргумента, не будет изменен этой функцией. Например:

// В реальных программах указатели на константы чаще всего

// употребляются как формальные параметры функций

int strcmp( const char *str1, const char *str2 );

(Мы еще поговорим об указателях на константы в главе 7, когда речь пойдет о функциях.)

Существуют и константные указатели. (Обратите внимание на разницу между константным указателем и указателем на константу!). Константный указатель может адресовать как константу, так и переменную. Например:

int errNumb = 0;

int *const currErr = errNumb;

Здесь curErr – константный указатель на неконстантный объект. Это значит, что мы не можем присвоить ему адрес другого объекта, хотя сам объект допускает модификацию. Вот как мог бы быть использован указатель curErr:

do_something();

if ( *curErr ) {

errorHandler();

*curErr = 0; // правильно: обнулим значение errNumb

}

Попытка присвоить значение константному указателю вызовет ошибку компиляции:

curErr = myErNumb; // ошибка

Константный указатель на константу является объединением двух рассмотренных случаев.

const double pi = 3.14159;

const double *const pi_ptr = pi;

Ни значение объекта, на который указывает pi_ptr, ни значение самого указателя не может быть изменено в программе.

Упражнение 3.16

Объясните значение следующих пяти определений. Есть ли среди них ошибочные?

(a) int i; (d) int *const cpi;

(b) const int ic; (e) const int *const cpic;

(c) const int *pic;

Упражнение 3.17

Какие из приведенных определений правильны? Почему?

(a) int i = -1;

(b) const int ic = i;

(c) const int *pic = ic;

(d) int *const cpi = ic;

(e) const int *const cpic = ic;

Упражнение 3.18

Используя определения из предыдущего упражнения, укажите правильные операторы присваивания. Объясните.

(a) i = ic; (d) pic = cpic;

(b) pic = ic; (i) cpic = ic;

(c) cpi = pic; (f) ic = *cpic;

3.6. Ссылочный тип

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