Screen( int hi = 8, int wid = 40, char bkground = '#');
// объявления других функций-членов не изменяются
};
Определение конструктора класса Screen выглядит так:
Screen::Screen( int hi, int wid, char bk ) :
_height( hi ), // инициализировать _height значением hi
_width( wid ), // инициализировать _width значением wid
_cursor ( 0 ), // инициализировать _cursor нулем
_screen( hi * wid, bk ) // размер экрана равен hi * wid
// все позиции инициализируются
// символом '#'
{ // вся работа проделана в списке инициализации членов
// этот список обсуждается в разделе 14.5
}
Каждый объявленный объект класса Screen автоматически инициализируется конструктором:
Screen s1; // Screen(8,40,'#')
Screen *ps = new Screen( 20 ); // Screen(20,40,'#')
int main() {
Screen s(24,80,'*'); // Screen(24,80,'*')
// ...
}
(В главе 14 конструкторы, деструкторы и операторы присваивания рассматриваются более подробно. В главе 15 обсуждаются конвертеры и функции управления памятью.)
13.3.5. Функции-члены со спецификаторами const и volatile
Любая попытка модифицировать константный объект из программы обычно помечается компилятором как ошибка. Например:
const char blank = ' ';
blank = '\n'; // ошибка
Однако объект класса, как правило, не модифицируется программой напрямую. Вместо этого вызывается та или иная открытая функция-член. Чтобы не было "покушений" на константность объекта, компилятор должен различать безопасные (те, которые не изменяют объект) и небезопасные (те, которые пытаются это сделать) функции-члены:
const Screen blankScreen;
blankScreen.display(); // читает объект класса
blankScreen.set( '*' ); // ошибка: модифицирует объект класса
Проектировщик класса может указать, какие функции-члены не модифицируют объект, объявив их константными с помощью спецификатора const:
class Screen {
public:
char get() const { return _screen[_cursor]; }
// ...
};
Для класса, объявленного как const, могут быть вызваны только те функции-члены, которые также объявлены со спецификатором const. Ключевое слово const помещается между списком параметров и телом функции-члена. Для константной функции-члена, определенной вне тела класса, это слово должно присутствовать как в объявлении, так и в определении:
class Screen {
public:
bool isEqual( char ch ) const;
// ...
private:
string::size_type _cursor;
string _screen;
// ...
};
bool Screen::isEqual( char ch ) const
{
return ch == _screen[_cursor];
}
Запрещено объявлять константную функцию-член, которая модифицирует члены класса. Например, в следующем упрощенном определении:
class Screen {
public:
int ok() const { return _cursor; }
void error( int ival ) const { _cursor = ival; }
// ...
private:
string::size_type _cursor;
// ...
};
определение функции-члена ok() корректно, так как она не изменяет значения _cursor. В определении же error() значение _cursor изменяется, поэтому такая функция-член не может быть объявлена константной и компилятор выдает сообщение об ошибке:
error: cannot modify a data member within a const member function
ошибка: не могу модифицировать данные-члены внутри константной функции-члена
Если класс будет интенсивно использоваться, лучше объявить его функции-члены, не модифицирующие данных, константными. Однако наличие спецификатора const в объявлении функции-члена не предотвращает все возможные изменения. Такое объявление гарантирует лишь, что функции-члены не смогут изменять данные-члены, но если класс содержит указатели, то адресуемые ими объекты могут быть модифицированы константной функцией, не вызывая ошибки компиляции. Это часто приводит в недоумение начинающих программистов. Например: