inline Screen& Screen::up()

{ // переместить _cursor на одну строку вверх

// если уже наверху, остаться на месте и подать сигнал

if ( row() == 1 ) // наверху?

cout BELL endl;

else

_cursor -= _width;

return *this;

}

inline Screen& Screen::down()

{

if ( row() == _height ) //внизу?

cout BELL endl;

else

_cursor += _width;

return *this;

}

row() – это закрытая функция-член, которая используется в функциях up() и down(), возвращая номер строки, где находится курсор:

inline int Screen::row()

{ // вернуть текущую строку

return ( _cursor + _width ) / height;

}

Пользователи класса Screen попросили нас добавить функцию repeat(), которая повторяет указанное действие n раз. Ее реализация могла бы выглядеть так:

Screen &repeat( char op, int times )

{

switch( op ) {

case DOWN: // n раз вызвать Screen::down()

break;

case DOWN: // n раз вызвать Screen::up()

break;

// ...

}

}

Такая реализация имеет ряд недостатков. В частности, предполагается, что функции-члены класса Screen останутся неизменными, поэтому при добавлении или удалении функции-члена repeat() необходимо модифицировать. Вторая проблема – размер функции. Поскольку приходится проверять все возможные функции-члены, то исходный текст становится громоздким и неоправданно сложным.

В более общей реализации параметр op заменяется параметром типа указателя на функцию-член класса Screen. Теперь repeat() не должна сама устанавливать, какую операцию следует выполнить, и всю инструкцию switch можно удалить. Определение и использование указателей на члены класса – тема последующих подразделов.

<p>13.6.1. Тип члена класса</p>

Указателю на функцию нельзя присвоить адрес функции-члена, даже если типы возвращаемых значений и списки параметров полностью совпадают. Например, переменная pfi – это указатель на функцию без параметров, которая возвращает значение типа int:

int (*pfi)();

Если имеются глобальные функции HeightIs() и WidthIs() вида:

int HeightIs();

int WidthIs();

то допустимо присваивание pfi адреса любой из этих переменных:

pfi = HeightIs;

pfi = WidthIs;

В классе Screen также определены две функции доступа, height() и width(), не имеющие параметров и возвращающие значение типа int:

inline int Screen::height() { return _height; }

inline int Screen::width() { return _width; }

Однако попытка присвоить их переменной pfi является нарушением типизации и влечет ошибку компиляции:

// неверное присваивание: нарушение типизации

pfi = &Screen::height;

В чем нарушение? У функций-членов есть дополнительный атрибут типа, отсутствующий у функций, не являющихся членами, – класс. Указатель на функцию-член должен соответствовать типу присваиваемой ему функции не в двух, а в трех отношениях: по типу и количеству формальных параметров; типу возвращаемого значения; типу класса, членом которого является функция.

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

Синтаксис объявления указателя на функцию-член должен принимать во внимание тип класса. То же верно и в отношении указателей на данные-члены. Рассмотрим член _height класса Screen. Его полный тип таков: член класса Screen типа short. Следовательно, полный тип указателя на _height – это указатель на член класса Screen типа short:

short Screen::*

Определение указателя на член класса Screen типа short выглядит следующим образом:

short Screen::*ps_Screen;

Переменную ps_Screen можно инициализировать адресом _height:

short Screen::*ps_Screen = &Screen::_height;

или присвоить ей адрес _width:

short Screen::*ps_Screen = &Screen::_width;

Перейти на страницу:

Похожие книги