Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП_ Лекция №05 - Вспомогательные средства для создания классов.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
75.16 Кб
Скачать

Указатели на члены

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

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

Предположим имеется структура, описывающая точку с двумя действительными координатами:

struct Point

{

double m_x;

double m_y;

};

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

// Определение указателя на переменную-член структуры Point типа double

double Point::* pCoordinate = ( какое-либо условие ) ?

& Point::m_x // В этой ветке инициализируем адресом поля m_x

: & Point::m_y ; // А в этой ветке — адресом поля m_y

// Модифицируем одно из полей, используя объект и указатель на переменную-член

Point p;

( p .* pCoordinate ) = 5;

// Читаем одно из полей, используя указатель на объект и указатель на переменную-член

Point * ptr = & p;

std::cout << ( ptr ->* pCoordinate );

Разумеется, нельзя взять указатель на член, если не совпадают типы данных указателя и поля.

Аналогично, можно воспользоваться указателями на функции-члены. Они декларируются подобно указателям на обычные функции, но дополнительно содержат имя класса и оператор разрешения области видимости (::) перед символом '*'. Для демонстрации данной конструкции языка преобразуем структуру-точку в класс и введем методы доступа:

class Point

{

double m_x;

double m_y;

public:

Point ( double _x, double _y );

double GetX () const { return m_x; }

double GetY () const { return m_y; }

void SetX ( double _x ) { m_x = _x; }

void SetY ( double _y ) { m_y = _y; }

};

Объявим два различных указателя на функции-член для соответствующих совместимых по интерфейсу пар методов GetX/GetY и SetX/SetY. Сделаем выбор в пользу конкретной координаты по некоторому условию, и воспользуемся объектом-точкой вместе со сформированными указателями для увеличения координаты на значение 2.5, а затем восстановим прежнее значение через указатель на объект-точку:

int main ()

{

// Указатель на метод из Point, возвращает double, // ничего не принимает, не меняет объект

double ( Point ::* pGetMethod ) () const;

// Указатель на метод из Point, не возвращает, // принимает аргумент double, меняет объект

void ( Point ::* pSetMethod ) ( double );

// Выбираем ту или иную координату для работы по некоторому произвольному условию.

// Для этого присваиваем указателям на методы адреса соответствующих методов

if ( некоторое условие )

{

pGetMethod = & Point::GetX;

pSetMethod = & Point::SetX;

}

else

{

pGetMethod = & Point::GetY;

pSetMethod = & Point::SetY;

}

// Создаем объект-точку

Point p( 3.5, 4.5 );

// Извлекаем текущую координату через объект p и указатель на метод

double currentCoordinate = ( p .* pGetMethod )();

// Обновляем текущую координату через объект p и указатель на метод

( p .* pSetMethod ) ( currentCoordinate + 2.5 );

// Берем адрес объекта

Point * ptr = & p;

// Извлекаем текущую координату через указатель на объект ptr и указатель на метод

currentCoordinate = ( ptr ->* pGetMethod ) ();

// Обновляем текущую координату через указатель на объект ptr и указатель на метод

( ptr ->* pSetMethod )( currentCoordinate – 2.5 );

}

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

class A

{

public:

// Статическая переменная-член

static int ms_data;

// Статическая функция-член

static int GetData () { return ms_data; }

};

// Определение статического члена

int A::ms_data;

int main ()

{

// Использование указателя на статическую переменную-член класса

const int * pData = & A::ms_data;

std::cout << * pData;

// Использование указателя на статическую функцию-член класса

int ( * pStaticMethod )() = & A::GetData;

std::cout << ( * pStaticMethod )();

}