Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
шпоры по ямп.docx
Скачиваний:
10
Добавлен:
01.04.2025
Размер:
161.76 Кб
Скачать

29.Указатели на члены класса.

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

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

Язык С++ предлагает средство косвенной ссылки на член класса. Указатель на член класса является значением, идентифицирующим член класса. Можно рассматривать его как позицию члена класса в объекте класса, но, конечно же, компилятор принимает в расчёт различия между данными, виртуальными функциями, невиртуальными функциями и т.д.

Указатель на член класса можно получить при помощи применения оператора взятия адреса & кполностью квалифицированному имени члена класса. Переменная типа «указатель на член класса X» объявляется с использование формы X::*.

Указатель на член класса m используется в комбинации с объектом. Операторы ->* и .* позволяют программисту выразить такую комбинацию. p->*m связывает m с объектом, на который указывает p, а obj.*mсвязывает m с объектом obj. Результат можно использовать в соответствии с типом m. Невозможно сохранить результат этих операций для его дальнейшего использования.Естественно, если бы мы знали, какой член класса нужно использовать, мы могли бы сделать это непосредственно, не используя указатели. Так же как и указатели на обычные функции, указатели на члены класса используются, когда возникает необходимость сослаться на объект, имя которого неизвестно. Однако в отличие от указателя на переменную или обычную функцию, указатель на член класса не является просто указателем на область памяти. Он больше соответствует смещению в структуре или индексу в массиве. Сочетание указателя на член класса с объектом или указателем на объект даёт то, что идентифицирует конкретный член конкретного объекта. class Base

{ public:

virtual void open() = 0;

virtual void close() = 0;

void print() { std::cout << "Base: print" << std::endl; }

virtual ~Base() { }

};

class D1 : public Base

{ public:

void open() { std::cout << "D1: open" << std::endl; }

void close() { std::cout << "D1: close" << std::endl; }

void print() { std::cout << "D1: print" << std::endl; }

};

class D2 : public Base

{ public:

void open() { std::cout << "D2: open" << std::endl; }

void close() { std::cout << "D2: close" << std::endl; }

void print() { std::cout << "D2: print" << std::endl; }

};

typedef void (Base::*PF)();

void main()

{ PF pf1 = &Base::open;

PF pf2 = &Base::close;

PF pf3 = &Base::print;

D1 d;

(d.*pf1)();

(d.*pf2)();

(d.*pf3)();

Base *pb = new D2;

(pb->*pf1)();

(pb->*pf2)();

(pb->*pf3)();

}

// Определяем тип для указателя на функцию-член класса Base

// Запоминаем указатели на члены класса Base

// (функции open и close являются виртуальными,

// а функция print – невиртуальной).

// d – объект класса D1

// Вызов функции D1::open()

// Вызов функции D1::close()

// Вызов функции Base::print()

// pb – указатель на объект класса Base (реально объект принадлежит классу D2)

// Вызов функции D2::open()

// Вызов функции D2::close()

// Вызов функции Base::print()