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

Screen& Screen::reSize( int h, int w, char bkground )

{ // сделать высоту экрана равной h, а ширину - равной w

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

string local(_screen);

// заменить строку _screen

_screen.assign( // записать в строку

h * w, // h * w символов

bkground // со значением bkground

);

typedef string::size_type idx_type;

idx_type local_pos = 0;

// скопировать содержимое старого экрана в новый

for ( idx_type ix = 0; ix _height; ++ix )

{ // для каждой строки

idx_type offset = w * ix; // смещение строки

for ( idx_type iy = 0; iy _width; ++iy )

// для каждой колонки присвоить новое значение

_screen[ offset + iy ] = local[ local_pos++ ];

}

_height = h;

_width = w;

// _cursor не меняется

return *this;

}

Работа указателя this не исчерпывается возвратом объекта, к которому была применена функция-член. При рассмотрении copy() в разделе 13.3 мы видели и другой способ его использования:

void Screen::copy( const Screen& sobj )

{

// если этот объект Screen и sobj - одно и то же,

// копирование излишне

if ( this != sobj )

{

// скопировать значение sobj в this

}

}

Указатель this хранит адрес объекта, для которого была вызвана функция-член. Если адрес, на который ссылается sobj, совпадает со значением this, то sobj и this относятся к одному и тому же объекту, так что операция копирования не нужна. (Мы еще встретимся с этой конструкцией, когда будем рассматривать копирующий оператор присваивания в разделе 14.7.)

Упражнение 13.7

Указатель this можно использовать для модификации адресуемого объекта, а также для его замены другим объектом того же типа. Например, функция-член assign() класса classType выглядит так. Можете ли вы объяснить, что она делает?

classType& classType::assign( const classType &source )

{

if ( this != &source )

{

this-~classType();

new (this) classType( source );

}

return *this;

}

Напомним, что ~classType – это имя деструктора. Оператор new выглядит несколько причудливо, но мы уже встречались с подобным в разделе 8.4.

Как вы относитесь к такому стилю программирования? Безопасна ли эта операция? Почему?

13.5. Статические члены класса

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

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

По сравнению с глобальным объектом у статического члена есть следующие преимущества:

* статический член не находится в глобальном пространстве имен программы, следовательно, уменьшается вероятность случайного конфликта имен с другими глобальными объектами;

* остается возможность сокрытия информации, так как статический член может быть закрытым, а глобальный объект – никогда.

Чтобы сделать член статическим, надо поместить в начале его объявления в теле класса ключевое слово static. К ним применимы все правила доступа к открытым, закрытым и защищенным членам. Например, для определенного ниже класса Account член _interestRate объявлен как закрытый и статический типа double:

class Account { // расчетный счет

Account( double amount, const string &owner );

string owner() { return _owner; }

private:

static double _interestRate; // процентная ставка

double _amount; // сумма на счету

string _owner; // владелец

};

Почему _interestRate сделан статическим, а _amount и _owner нет? Потому что у всех счетов разные владельцы и суммы, но процентная ставка одинакова. Следовательно, объявление члена _interestRate статическим уменьшает объем памяти, необходимый для хранения объекта Account.