19.4.1. Указатели на переменные-члены
Подобно любым указателям, при объявлении указателя на член класса используется символ *, означающий, что объявляемое имя является указателем. В отличие от обычных указателей, указатель на член класса включает также имя класса, содержащего этот член. Следовательно, символу * должна предшествовать часть имяКласса::, означающая, что определяемый указатель способен указывать на член класса имяКласса. Например:
// pdata может указывать на член типа string константного (или не
// константного) объекта класса Screen
const string Screen::*pdata;
Приведенный выше код объявляет pdata "указателем на член класса Screen, обладающий типом const string". Переменные-члены константного объекта сами являются константами. Объявление указателя pdata как указателя на тип const string позволяет использовать его для указания на член любого объекта класса Screen, константного или нет. Взамен указатель pdata применим только для чтения, но не для записи в член класса, на который он указывает.
При инициализации (или присвоении) указателя на член класса следует заявить, на который член он указывает. Например, можно заставить указать pdata указывать на переменную-член contents неопределенного объекта класса Screen следующим образом:
pdata = &Screen::contents;
Здесь оператор обращения к адресу применяется не к объекту в памяти, а к члену класса Screen.
Конечно, по новому стандарту проще объявить указатель на член класса при помощи ключевых слов auto или decltype:
auto pdata = &Screen::contents;
Использование указателей на переменные-члены
Важно понять, что при инициализации или присвоении указателя на член класса он еще не указывает на данные. Он идентифицирует определенный член класса, но не содержащий его объект. Объект предоставляется при обращении к значению указателя на член класса.
Подобно операторам доступа к членам (member access operator), . и ->, существуют два оператора доступа к указателю на член класса, .* и ->*, позволяющие предоставить объект и обращаться к значению указателя для доступа к члену этого объекта:
Screen myScreen, *pScreen = &myScreen;
// .* обращение к значению pdata для доступа к содержимому члена данного
// объекта класса myScreen
auto s = myScreen.*pdata;
// ->* обращение к значению pdata для доступа к содержимому члена
// объекта, на который указывает pScreen
s = pScreen->*pdata;
Концептуально эти операторы выполняют два действия: обращаются к значению указателя на член класса, чтобы получить доступ к необходимому члену; затем, подобно операторам обращения к членам, они обращаются к члену данного объекта непосредственно (.*) или через указатель (->*).
Функция, возвращающая указатель на переменную-член
К указателям на члены применимы обычные средства управления доступом. Например, член contents класса Screen является закрытым. В результате указатель pdata выше должен использоваться в члене класса Screen, его дружественном классе, либо произойдет ошибка.
Поскольку переменные-члены обычно являются закрытыми, как правило, нельзя получать указатель на саму переменную-член. Вместо этого, если такой класс, как Screen, желает предоставить доступ к своему члену contents, то он определил бы функцию, возвращающую указатель на эту переменную-член:
class Screen {
public:
// data() - статический член, возвращающий указатель на член класса
static const std::string Screen::*data()
{ return &Screen::contents; }
// другие члены, как прежде
};
Здесь в класс Screen добавлена статическая функция-член, возвращающая указатель на переменную-член contents класса Screen. Тип возвращаемого значения этой функции совпадает с типом первоначального указателя pdata. Читая тип возвращаемого значения справа налево, можно заметить, что функция data() возвращает указатель на член класса Screen, имеющий тип string и являющийся константой. Тело функции применяет оператор обращения к адресу к переменной-члену contents. Таким образом, функция возвращает указатель на переменную-член contents класса Screen.
Когда происходит вызов функции data(), возвращается указатель на член класса:
// data() возвращает указатель на член contents класса Screen
const string Screen::*pdata = Screen::data();
Как и прежде, указатель pdata указывает на член класса Screen, но не на фактические данные. Чтобы использовать указатель pdata, следует связать его с объектом типа Screen:
// получить содержимое объекта myScreen
auto s = myScreen.*pdata;
Упражнения раздела 19.4.1
Упражнение 19.11. В чем разница между обычным указателем на данные и указателем на переменную-член?
Упражнение 19.12. Определите указатель на член класса, способный указывать на член cursor класса Screen. Получите через этот указатель значение Screen::cursor.
Упражнение 19.13. Определите тип, способный представить указатель на член bookNo класса Sales_data.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОК