Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих (Стенли Липпман) 3-е хххх.pdf
Скачиваний:
86
Добавлен:
30.05.2015
Размер:
5.92 Mб
Скачать

С++ для начинающих

600

Откомпилировав и запустив эту программу, мы получим следующее:

Screen Object ( 3, 3 )

abc def ghi

13.3.4. Специальные функции-члены

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

class Screen { public:

Screen( int hi = 8, int wid = 40, char bkground = '#'); // объявления других функций-членов не изменяются

умолчанию для параметров hi, wid и bkground:

};

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 автоматически инициализируется

 

 

 

Каждый объявленный объект

 

 

Screen s1;

// Screen(8,40,'#')

 

 

 

 

Screen *ps = new Screen( 20 ); // Screen(20,40,'#')

 

 

int main() {

// Screen(24,80,'*')

 

 

Screen s(24,80,'*');

 

 

// ...

 

конструктором:

 

 

 

}

 

 

 

 

 

 

 

С++ для начинающих

601

(В главе 14 конструкторы, деструкторы и операторы присваивания рассматриваются более подробно. В главе 15 обсуждаются конвертеры и функции управления памятью.)

13.3.5. Функции-члены со спецификаторами const и volatile

Любая попытка модифицировать константный объект из программы обычно помечается

const char blank = ' ';

компилятором как ошибка. Например:

blank = '\n';

// ошибка

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

const Screen blankScreen;

// читает объект класса

blankScreen.display();

изменяют объект) и небезопасные (те, которые пытаются это сделать) функции-члены:

blankScreen.set( '*' );

// ошибка: модифицирует объект класса

Проектировщик класса может указать, какие функции-члены не модифицируют объект,

class Screen { public:

char get() const { return _screen[_cursor]; } // ...

объявив их константными с помощью спецификатора const:

};

Для класса, объявленного как const, могут быть вызваны только те функции-члены, которые также объявлены со спецификатором const. Ключевое слово const помещается между списком параметров и телом функции-члена. Для константной функции-члена, определенной вне тела класса, это слово должно присутствовать как в объявлении, так и в определении:

С++ для начинающих

602

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 в объявлении функции-члена не предотвращает все возможные изменения. Такое объявление гарантирует лишь, что функции-члены не смогут изменять данные-члены, но если класс содержит указатели, то адресуемые ими объекты могут быть модифицированы константной функцией, не вызывая ошибки компиляции. Это часто приводит в недоумение начинающих программистов. Например:

С++ для начинающих

603

#include <cstring>

class Text { public:

void bad( const string &parm ) const; private:

char *_text;

};

void Text::bad( const string &parm ) const

{

_text = parm.c_str(); // ошибка: нельзя модифицировать _text

for ( int ix = 0; ix < parm.size(); ++ix )

_text[ix] = parm[ix]; // плохой стиль, но не ошибка

}

Модифицировать _text нельзя, но это объект типа char*, и символы, на которые он указывает, можно изменить внутри константной функции-члена класса Text. Функция- член bad() демонстрирует плохой стиль программирования. Константность функции- члена не гарантирует, что объекты внутри класса останутся неизменными после ее вызова, причем компилятор не поможет обнаружить такую ситуацию.

Константную функцию-член можно перегружать неконстантной функцией с тем же

class Screen { public:

char get(int x, int y);

char get(int x, int y) const; // ...

списком параметров:

};

В этом случае наличие спецификатора const у объекта класса определяет, какая из двух

int main() {

const Screen cs; Screen s;

char

ch = cs.get(0,0);

//

вызывает

константную функцию-член

ch =

s.get(0,0);

//

вызывает

неконстантную функцию-член

функций будет вызвана:

}

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

трактуется как константный с момента завершения работы конструктора и до вызова деструктора.