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

#include "Screen.h" #include <iostream>

int main() {

Screen sobj(3,3); // конструктор определен в разделе 13.3.4

string init("abcdefghi"); cout << "Screen Object ( "

<<sobj.height() << ", "

<<sobj.width() << " )\n\n";

//Задать содержимое экрана string::size_type initpos = 0;

for ( int ix = 1; ix <= sobj.width(); ++ix )

for ( int iy = 1; iy <= sobj.height(); ++iy )

{

sobj.move( ix, iy ); sobj.set( init[ initpos++ ] );

}

// Напечатать содержимое экрана

for ( int ix = 1; ix <= sobj.width(); ++ix )

{

for ( int iy = 1; iy <= sobj.height(); ++iy ) cout << sobj.get( ix, iy );

cout << "\n";

}

return 0;

}

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

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 значением

_width( wid ),

wid

// инициализировать _cursor нулем

_cursor ( 0 ),

_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 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( '*' );

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

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

class Screen { public:

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

// ...

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

};

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

#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 у объекта класса определяет, какая из двух функций будет вызвана: