С++ для начинающих
508 Resource Limit Is Reached

Resource Limit Is Reached

The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.

Когда использовать указатель this


Наша функция main() вызывает функции-члены класса Screen для объектов myScreen и bufScreen таким образом, что каждое действие– это отдельная инструкция. У нас есть возможность определить функции-члены так, чтобы конкатенировать их вызовы при обращении к одному и тому же объекту. Например, все вызовы внутри main() будут выглядеть так:

int main() {

   // ...

   myScreen.clear().move( 2, 2 ), set( '*' ). display();

   bufScreen.reSize( 5, 5 ).display();

}

Именно так интуитивно представляется последовательность операций с экраном: очистить экран myScreen, переместить курсор в позицию (2,2), записать в эту позицию символ '*' и вывести результат.

Операторы доступа “точка” и “стрелка” левоассоциативны, т.е. их последовательность выполняется слева направо. Например, сначала вызывается myScreen.clear(), затем myScreen.move() и т.д. Чтобы myScreen.move() можно было вызвать после myScreen.clear(), функция clear() должна возвращать объект myScreen, для которого она была вызвана. Мы уже видели, что доступ к объекту внутри функции-члена класса производится в помощью указателя this. Вот реализация clear():

// объявление clear() находится в теле класса

// в нем задан аргумент по умолчанию bkground = '#'

Screen& Screen::clear( char bkground )

{ // установить курсор в левый верхний угол и очистить экран

   _cursor = 0;

508 Resource Limit Is Reached

Resource Limit Is Reached

The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.

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

      _screen.size(),    // size() символов

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

   );

   // вернуть объект, для которого была вызвана функция

   return *this;

}

Обратите внимание, что возвращаемый тип этой функции-члена – Screen& – ссылка на объект ее же класса. Чтобы конкатенировать вызовы, необходимо также пересмотреть реализацию move() и set(). Возвращаемый тип следует изменить с void на Screen&, а в определении возвращать *this.

Аналогично функцию-член display() можно написать так:

Screen& Screen::display()

{

   typedef string::size_type idx_type;


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

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

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

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

          // для каждой колонки вывести элемент

          cout << _screen[ offset + iy ];

          cout << endl;

        }

        return *this;

}

А вот реализация reSize():

// объявление reSize() находится в теле класса

// в нем задан аргумент по умолчанию bkground = '#'

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.

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


Содержание раздела

508 Resource Limit Is Reached

Resource Limit Is Reached

The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.