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

Сначала мы определим новый член 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 "не могу инкрементировать указатель для одного объекта\n";

return *ptr;

}

if ( offset = size - 1 ) {

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

return *ptr;

}

++offset;

return *++ptr;

}

Screen& ScreenPtr::operator--()

{

if ( size == 0 ) {

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

return *ptr;

}

if ( offset = 0 ) {

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

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 "не могу инкрементировать указатель для одного объекта\n";

return *ptr;

}

if ( offset == size ) {

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

return *ptr;

}

++offset;

return *ptr++;

}

Screen& ScreenPtr::operator--(int)

{

if ( size == 0 ) {

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

return *ptr;

}

if ( offset == -1 ) {

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

return *ptr;

}

--offset;

return *ptr--;

}