|
Программирование >> Инициализация объектов класса, структура
int main() { Screen myScreen( 3, 3 ), bufScreen; myScreen.clear() ; myScreen.move( 2, 2 ); myScreen.set( * ); myScreen.display(); bufScreen.resize( 5, 5 ); bufScreen.display(); У каждого объекта класса есть собственная копия данных-членов. Например: У объекта myScreen есть свои члены width, height, cursor и screen, а у объекта bufScreen - свои. Однако каждая функция-член класса существует в единственном экземпляре. Их и вызывают myScreen и bufScreen. В предыдущем разделе мы видели, что функция-член может обращаться к членам своего класса, не используя операторы доступа. Так, определение функции move() выглядит inline void Screen::move( int r, int c ) if ( checkRange( r, c ) ) позиция на экране задана корректно? int row = (r-1) * width; смещение строки cursor = row + c - 1; следующим образом: Если функция move() вызывается для объекта myScreen, то члены width и height, к которым внутри нее имеются обращения, - это члены объекта myScreen. Если же она вызывается для объекта bufScreen, то и обращения производятся к членам данного К дополнительным перемещениям курсора можно отнести его передвижение вперед и назад на один символ. Из правого нижнего угла экрана курсор должен попасть в левый верхний угол. Реализуйте функции forward() и backward() . Упражнение 13.5 Еще одной полезной возможностью является перемещение курсора вниз и вверх на одну строку. По достижении верхней или нижней строки экрана курсор не перепрыгивает на противоположный край; вместо этого подается звуковой сигнал, и курсор остается на месте. Реализуйте функции up() и down() . Для подачи сигнала следует вывести на стандартный вывод cout символ с кодом 007. Упражнение 13.6 Пересмотрите описанные функции-члены класса Screen и объявите те, которые сочтете нужными, константными. Объясните свое решение. 13.4. Неявный указатель this псевдокод, показывающий, как происходит расширение определения функции-члена ЭТО НЕ КОРРЕКТН КОД C++ inline void Screen::move( Screen *this, int r, int c ) { if ( checkRange( r, c ) ) int row = (r-1) * this-> width; this-> cursor = row + c - 1; 1. Изменить определение функции-члена класса, добавив дополнительный параметр: В этом определении использование указателя this для доступа к членам width и cursor сделано явным. 2. Изменение каждого вызова функции-члена класса с целью передачи одного дополнительного аргумента - адреса объекта, для которого она вызвана: myScreen.move( 2, 2 ); транслируется в move( smyScreen, 2, 2 ); Программист может явно обращаться к указателю this внутри функции. Так, вполне inline void Screen::home() this-> cursor = 0; корректно, хотя и излишне, определить функцию-член home() следующим образом: объекта. Каким же образом cursor, которым манипулирует move(), оказывается членом то myScreen, то bufScreen? Дело в указателе this. Каждой функции-члену передается указатель на объект, для которого она вызвана, -this. В неконстантной функции-члене это указатель на тип класса, в константной -константный указатель на тот же тип, а в функции со спецификатором volatile указатель с тем же спецификатором. Например, внутри функции-члена move() класса Screen указатель this имеет тип Screen*, а в неконстантной функции-члене List - тип List*. Поскольку this адресует объект, для которого вызвана функция-член, то при вызове move() для myScreen он указывает на объект myScreen, а при вызове для bufScreen -на объект bufScreen. Таким образом, член cursor, с которым работает функция move() , в первом случае принадлежит объекту myScreen, а во втором - bufScreen. Понять все это можно, если представить себе, как компилятор реализует объект this. Для его поддержки необходимо две трансформации: int main() { ... myScreen.clear().move( 2, 2 ), set( * ). display(); myScreen.clear().move( 2, 2 ), set( bufScreen.reSize( 5, 5 ).display(); выглядеть так: Именно так интуитивно представляется последовательность операций с экраном: очистить экран myScreen, переместить курсор в позицию (2,2), записать в эту позицию символ * и вывести результат. Операторы доступа точка и стрелка левоассоциативны, т.е. их последовательность выполняется слева направо. Например, сначала вызывается myScreen.clear() , затем myScreen.move() и т. д. Чтобы myScreen.move() можно было вызвать после myScreen.clear() , функция clear() должна возвращать объект myScreen, для которого она была вызвана. Мы уже видели, что доступ к объекту внутри функции-члена объявление clear() находится в теле класса в нем задан аргумент по умолчанию bkground = # Screens Screen::clear( char bkground ) { установить курсор в левый верхний угол и очистить экран cursor = 0; screen.assign( записать в строку screen.size(), size() символов bkground со значением bkground вернуть объект, для которого была вызвана функция return *this; класса производится в помощью указателя this. Вот реализация clear() : Обратите внимание, что возвращаемый тип этой функции-члена - Screen& - ссылка на объект ее же класса. Чтобы конкатенировать вызовы, необходимо также пересмотреть реализацию move() и set() . Возвращаемый тип следует изменить с void на Screen&, а в определении возвращать *this. Аналогично функцию-член display () можно написать так: Однако бывают случаи, когда без такого обращения не обойтись, как мы видели на примере функции-члена copy() класса Screen. В следующем подразделе мы рассмотрим и другие примеры. 13.4.1. Когда использовать указатель this Наша функция main() вызывает функции-члены класса Screen для объектов myScreen и bufScreen таким образом, что каждое действие - это отдельная инструкция. У нас есть возможность определить функции-члены так, чтобы конкатенировать их вызовы при обращении к одному и тому же объекту. Например, все вызовы внутри main() будут
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |