15.7. Операторы инкремента и декремента

15.7. Операторы инкремента и декремента

Продолжая развивать реализацию класса ScreenPtr, введенного в предыдущем разделе, рассмотрим еще два оператора, которые поддерживаются для встроенных указателей и которые желательно иметь и для нашего интеллектуального указателя: инкремент (++) и декремент (--). Чтобы использовать класс ScreenPtr для ссылки на элементы массива объектов Screen, туда придется добавить несколько дополнительных членов.

Сначала мы определим новый член size, который содержит либо нуль (это говорит о том, что объект ScreenPtr указывает на единственный объект), либо размер массива, адресуемого объектом ScreenPtr. Нам также понадобится член offset, запоминающий смещение от начала данного массива:

class ScreenPtr {

public:

// ...

private:

int size; // размер массива: 0, если единственный объект

int offset; // смещение ptr от начала массива

Screen *ptr;

};

Модифицируем конструктор класса ScreenPtr с учетом его новой функциональности и дополнительных членов,. Пользователь нашего класса должен передать конструктору дополнительный аргумент, если создаваемый объект указывает на массив:

class ScreenPtr {

public:

ScreenPtr( Screen &s , int arraySize = 0 )

: ptr( &s ), size ( arraySize ), offset( 0 ) { }

private:

int size;

int offset;

Screen *ptr;

};

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

Screen myScreen( 4, 4 );

ScreenPtr pobj( myScreen ); // правильно: указывает на один объект

const int arrSize = 10;

Screen *parray = new Screen[ arrSize ];

ScreenPtr parr( *parray, arrSize ); // правильно: указывает на массив

Теперь мы готовы определить в ScreenPtr перегруженные операторы инкремента и декремента. Однако они бывают двух видов: префиксные и постфиксные. К счастью, можно определить оба варианта. Для префиксного оператора объявление не содержит ничего неожиданного:

class ScreenPtr {

public:

Screen& operator++();

Screen& operator--();

// ...

};

Такие операторы определяются как унарные операторные функции. Использовать префиксный оператор инкремента можно, к примеру, следующим образом: const int arrSize = 10; Screen *parray = new Screen[ arrSize ]; ScreenPtr parr( *parray, arrSize ); for ( int ix = 0; ix

Определения этих перегруженных операторов приведены ниже:

Screen& ScreenPtr::operator++()

{

if ( size == 0 ) {

cerr "не могу инкрементировать указатель для одного объекта ";

return *ptr;

}

if ( offset = size - 1 ) {

cerr "уже в конце массива ";

return *ptr;

}

++offset;

return *++ptr;

}

Screen& ScreenPtr::operator--()

{

if ( size == 0 ) {

cerr "не могу декрементировать указатель для одного объекта ";

return *ptr;

}

if ( offset = 0 ) {

cerr "уже в начале массива ";

return *ptr;

}

--offset;

return *--ptr;

}

Чтобы отличить префиксные операторы от постфиксных, в объявлениях последних имеется дополнительный параметр типа int. В следующем фрагменте объявлены префиксные и постфиксные варианты операторов инкремента и декремента для класса ScreenPtr:

class ScreenPtr {

public:

Screen& operator++(); // префиксные операторы

Screen& operator--();

Screen& operator++(int); // постфиксные операторы

Screen& operator--(int);

// ...

};

Ниже приведена возможная реализация постфиксных операторов:

Screen& ScreenPtr::operator++(int)

{

if ( size == 0 ) {

cerr "не могу инкрементировать указатель для одного объекта ";

return *ptr;

}

if ( offset == size ) {

cerr "уже на один элемент дальше конца массива ";

return *ptr;

}

++offset;

return *ptr++;

}

Screen& ScreenPtr::operator--(int)

{

if ( size == 0 ) {

cerr "не могу декрементировать указатель для одного объекта ";

return *ptr;

}

if ( offset == -1 ) {

cerr "уже на один элемент раньше начала массива ";

return *ptr;

}

--offset;

return *ptr--;

}

Обратите внимание, что давать название второму параметру нет необходимости, поскольку внутри определения оператора он не употребляется. Компилятор сам подставляет для него значение по умолчанию, которое можно игнорировать. Вот пример использования постфиксного оператора:

const int arrSize = 10;

Screen *parray = new Screen[ arrSize ];

ScreenPtr parr( *parray, arrSize );

for ( int ix = 0; ix

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

parr.operator++(1024); // вызов постфиксного operator++

Перегруженные операторы инкремента и декремента разрешается объявлять как дружественные функции. Изменим соответствующим образом определение класса ScreenPtr:

class ScreenPtr {

// объявления не членов

friend Screen& operator++( Screen & ); // префиксные операторы

friend Screen& operator--( Screen & );

friend Screen& operator++( Screen &, int); // постфиксные операторы

friend Screen& operator--( Screen &, int);

public:

// определения членов

};

Упражнение 15.7

Напишите определения перегруженных операторов инкремента и декремента для класса ScreenPtr, предположив, что они объявлены как друзья класса.

Упражнение 15.8

С помощью ScreenPtr можно представить указатель на массив объектов класса Screen. Модифицируйте перегруженные operator*() и operator () (см. раздел 15.6) так, чтобы указатель ни при каком условии не адресовал элемент перед началом или за концом массива. Совет: в этих операторах следует воспользоваться новыми членами size и offset.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Операторы

Из книги Давайте создадим компилятор! автора Креншоу Джек


5.3.3 Операторы && и ||

Из книги Linux для пользователя автора Костромин Виктор Алексеевич

5.3.3 Операторы && и || Операторы и || являются управляющими операторами. Если в командной строке стоит command1 command2, то command2 выполняется в том, и только в том случае, если статус выхода из команды command1 равен нулю, что говорит об успешном ее завершении. Аналогично, если


5.5.1 Операторы ›, ‹ и ››

Из книги Справочное руководство по C++ автора Страустрап Бьярн

5.5.1 Операторы ›, ‹ и ›› Для обозначения перенаправления используются символы "›", "‹" и "››". Чаще всего используется перенаправление вывода команды в файл. Вот соответствующий пример:[user]$ ls -l › /home/jim/dir.txtПо этой команде в файле /home/jim/dir.txt будет сохранен перечень файлов и


R.6 Операторы

Из книги Windows Script Host для Windows 2000/XP автора Попов Андрей Владимирович

R.6 Операторы Все операторы, за исключением оговоренных случаев, выполняются один за


Операторы

Из книги HTML 5, CSS 3 и Web 2.0. Разработка современных Web-сайтов. автора Дронов Владимир

Операторы В JScript поддерживаются операторы различных типов, которые похожи на операторы языка


Операторы отношения и логические операторы

Из книги HTML 5, CSS 3 и Web 2.0. Разработка современных Web-сайтов автора Дронов Владимир

Операторы отношения и логические операторы Операторы отношения используются для сравнения значений двух переменных. Эти операторы, описанные в табл. П2.11, могут возвращать только логические значения true или false.Таблица П2.11. Операторы отношения Оператор Условие, при


Операторы

Из книги C++. Сборник рецептов автора Диггинс Кристофер

Операторы Операторов язык JavaScript поддерживает очень много — на все случаи жизни. Их можно разделить на несколько групп. Арифметические операторы Арифметические операторы служат для выполнения арифметических действий над числами. Все арифметические операторы,


Операторы 

Из книги Язык программирования Си для персонального компьютера автора Бочков C. О.

Операторы  Операторов язык JavaScript поддерживает очень много — на все случаи жизни. Их можно разделить на несколько


Операторы SQL

Из книги Linux и UNIX: программирование в shell. Руководство разработчика. автора Тейнсли Дэвид

Операторы SQL Оператор SQL используется для выполнения запроса к базе данных. Язык запросов выражается в операторах, которые задают цель: что должно быть сделано (операция), объекты, с которыми это должно быть сделано, и детализация, как это должно быть сделано. По теории


Операторы SQL

Из книги C++ для начинающих автора Липпман Стенли

Операторы SQL Синтаксис SQL Firebird включает операторы для сравнения и вычисления значений столбцов, констант, переменных и выражений встраиваемого SQL для получения различных утверждений. Приоритет операторов Приоритет определяет порядок, в котором операторы и создаваемые


8.1. Операторы

Из книги Описание языка PascalABC.NET автора Коллектив РуБоард

8.1. Операторы присваиваниеvariable assignmentИнициализация переменной или изменение ее значения=Универсальный оператор присваивания, пригоден как для сравнения целых чисел, так и для сравнения строк.var=27category=minerals # Пробелы до и после оператора "=" -- недопустимы. Пусть вас не


4.5. Операции инкремента и декремента

Из книги автора

4.5. Операции инкремента и декремента Операции инкремента (++) и декремента (--) дают возможность компактной и удобной записи для изменения значения переменной на единицу. Чаще всего они используются при работе с массивами и коллекциями – для изменения величины индекса,


Операторы

Из книги автора

Операторы Операторы: обзор В PascalABC.NET определены следующие операторы.Операторы присваиванияСоставной операторОператор описания переменнойОператор цикла forОператор цикла foreachОператоры цикла while и repeatУсловный оператор ifОператор выбора варианта caseОператор вызова