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

Объявление указателя на статический член класса выглядит так же, как и для указателя на объект, не являющийся членом класса. Для разыменования указателя никакой объект не требуется. Рассмотрим класс Account:

class Account {

public:

static void raiseInterest( double incr );

static double interest() { return _interestRate ; }

double amount() { return _amount; }

private:

static double _interestRate;

double _amount;

string _owner;

};

inline void Account::raiseInterest( double incr )

{

_interestRate += incr;

}

Тип &_interestRate – это double*:

// это неправильный тип для &_interestRate

double Account::*

Определение указателя на &_interestRate имеет вид:

// правильно: double*, а не double Account::*

double *pd = &Account::_interestRate;

Этот указатель разыменовывается так же, как и обычный, объект класса для этого не требуется:

Account unit;

// используется обычный оператор разыменования

double daily = *pd / 365 * unit._amount;

Однако, поскольку _interestRate и _amount – закрытые члены, необходимо иметь статическую функцию-член interest() и нестатическую amount().

Указатель на interest() – это обычный указатель на функцию:

// правильно

double (*)()

а не на функцию-член класса Account:

// неправильно

double (Account::*)()

Определение указателя и косвенный вызов interest() реализуются так же, как и для обычных указателей:

// правильно: double(*pf)(), а не double(Account::*pf)()

double(*pf)() = &Account::interest;

double daily = pf() / 365 * unit.amount();

Упражнение 13.11

К какому типу принадлежат члены _screen и _cursor класса Screen?

Упражнение 13.12

Определите указатель на член и инициализируйте его значением Screen::_screen; присвойте ему значение Screen::_cursor.

Упражнение 13.13

Определите typedef для каждой из функций-членов класса Screen.

Упражнение 13.14

Указатели на члены можно также объявлять как данные-члены класса. Модифицируйте определение класса Screen так, чтобы оно содержало указатель на его функцию-член того же типа, что home() и end().

Упражнение 13.15

Модифицируйте имеющийся конструктор класса Screen (или напишите новый) так, чтобы он принимал параметр типа указателя на функцию-член класса Screen, для которой список формальных параметров и тип возвращаемого значения такие же, как у home() и end(). Реализуйте для этого параметра значение по умолчанию и используйте параметр для инициализации члена класса, описанного в упражнении 13.14. Напишите функцию-член Screen, позволяющую пользователю задать ее значение.

Упражнение 13.16

Определите перегруженный вариант repeat(), который принимает параметр типа cursorMovements.

13.7. Объединение – класс, экономящий память

Объединение – это специальный вид класса. Данные-члены хранятся в нем таким образом, что перекрывают друг друга. Все члены размещаются, начиная с одного и того же адреса. Для объединения отводится столько памяти, сколько необходимо для хранения самого большого его члена. В любой момент времени можно присвоить значение лишь одному такому члену.

Рассмотрим пример, иллюстрирующий использование объединения. Лексический анализатор, входящий в состав компилятора, разбивает программу на последовательность лексем. Так, инструкция

int i = 0;

преобразуется в последовательность из пяти лексем:

* Ключевое слово int.

* Идентификатор i.

* Оператор =

* Константа 0 типа int.

* Точка с запятой.

Лексический анализатор передает эти лексемы синтаксическому анализатору, парсеру, который идентифицирует полученную последовательность. Полученная информация должна дать парсеру возможность распознать эту последовательность лексем как объявление. Для этого с каждой лексемой ассоциируется информация, позволяющая парсеру увидеть следующее:

Type ID Assign Constant Semicolon

(Тип ИД Присваивание Константа Точка с запятой)

Далее парсер анализирует значения каждой лексемы. В данном случае он видит:

Type == int

ID == i

Constant == 0

Для Assign и Semicolon дополнительной информации не нужно, так как у них может быть только одно значение: соответственно := и ;

Таким образом, в представлении лексемы могло бы быть два члена – token и value. token – это уникальный код, показывающий, что лексема имеет тип Type, ID, Assign, Constant или Semicolon, например 85 для ID и 72 для Semicolon.value содержит конкретное значение лексемы. Так, для лексемы ID в предыдущем объявлении value будет содержать строку "i", а для лексемы Type – некоторое представление типа int.