Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих.pdf
Скачиваний:
183
Добавлен:
01.05.2014
Размер:
3.97 Mб
Скачать

int main() {

const Screen cs; Screen s;

char ch = cs.get(0,0);

// вызывает константную функцию-член

ch = s.get(0,0);

// вызывает неконстантную функцию-

член

 

}

 

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

Функцию-член можно также объявить со спецификатором volatile (он был введен в

разделе 3.13). Объект класса объявляется как volatile, если его значение изменяется способом, который не обнаруживается компилятором (например, если это структура данных, представляющая порт ввода/вывода). Для таких объектов вызываются только

class Screen { public:

char poll() volatile;

// ...

};

функции-члены с тем же спецификатором, конструкторы и деструкторы: char Screen::poll() volatile { ... }

13.3.6. Объявление mutable

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

const Screen cs ( 5, 5 );

Если мы хотим прочитать символ, находящийся в позиции (3,4), то попробуем сделать

//прочитать содержимое экрана в позиции (3,4)

//Увы! Это не работает

cs.move( 3, 4 );

так:

char ch = cs.get();

Но такая конструкция не работает: move() – это не константная функция-член, и сделать ее таковой непросто. Определение move() выглядит следующим образом:

inline void Screen::move( int r, int c )

{

if ( checkRange( r, c ) )

 

{

 

int row = (r-1) * _width;

// модифицирует

_cursor = row + c - 1;

_cursor

 

}

 

}

Обратите внимание, что move()изменяет член класса _cursor, следовательно, не может быть объявлена константной.

Но почему нельзя модифицировать _cursor для константного объекта класса Screen? Ведь _cursor – это просто индекс. Изменяя его, мы не модифицируем содержимое экрана, а лишь пытаемся установить позицию внутри него. Модификация _cursor должна быть разрешена несмотря на то, что у класса Screen есть спецификатор const.

Чтобы разрешить модификацию члена класса, принадлежащего константному объекту, объявим его изменчивым (mutable). Член с таким спецификатором не бывает константным, даже если он член константного объекта. Его можно обновлять, в том числе функцией-членом со спецификатором const. Объявлению изменчивого члена

class Screen {

 

public:

 

// функции-члены

 

private:

_screen;

string

mutable string::size_type

_cursor; // изменчивый

член

_height;

short

short

_width;

класса должно предшествовать ключевое слово mutable:

};

Теперь любая константная функция способна модифицировать _cursor, и move() может быть объявлена константной. Хотя move() изменяет данный член, компилятор не считает

// move() - константная функция-член

inline void Screen::move( int r, int c ) const

{

//...

//правильно: константная функция-член может модифицировать члены

//со спецификатором mutable

_cursor = row + c - 1;

// ...

это ошибкой.

}

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