Бьерн Страуструп. Язык программирования С++ Второе дополненное издание



Pdf көрінісі
бет146/256
Дата11.07.2022
өлшемі2,87 Mb.
#37591
1   ...   142   143   144   145   146   147   148   149   ...   256
7.9 Косвенное обращение 
Операцию косвенного обращения к члену -> можно определить как унарную постфиксную операцию. 
Это значит, если есть класс 
class Ptr { 
// 
... 
X* 
operator->(); 
}; 
объекты класса Ptr могут использоваться для доступа к членам класса X также, как для этой цели 
используются указатели: 
void f(Ptr p) 

p->m = 7;
// (p.operator->())->m = 7 

Превращение объекта p в указатель p.operator->() никак не зависит от члена m, на который он 
указывает. Именно по этой причине operator->() является унарной постфиксной операцией. Однако, мы 
не вводим новых синтаксических обозначений, так что имя члена по-прежнему должно идти после -> : 
void g(Ptr p) 

X* q1 = p->; 
// синтаксическая ошибка 
X* q2 = p.operator->(); 
// нормально 

Перегрузка операции -> прежде всего используется для создания "хитрых указателей", т.е. объектов, 
которые помимо использования как указатели позволяют проводить некоторые операции при каждом 
обращении к указуемому объекту с их помощью. Например, можно определить класс RecPtr для 
организации доступа к объектам класса Rec, хранимым на диске. Параметром конструктора RecPtr 
является имя, которое будет использоваться для поиска объекта на диске. При обращении к объекту с 
помощью функции RecPtr::operator->() он переписывается в основную память, а в конце работы 
деструктор RecPtr записывает измененный объект обратно на диск. 
class RecPtr { 
Rec* 
in_core_address; 
const char* identifier; 
// 
... 
public: 
RecPtr(const 
char* 
p) 
: identifier(p) { in_core_address = 0; } 
~RecPtr() 

write_to_disc(in_core_address,identifier); 

Rec* 
operator->(); 
}; 
Rec* RecPtr::operator->() 

if (in_core_address == 0) 
in_core_address 

read_from_disc(identifier); 
return 
in_core_address; 

Использовать это можно так: 
main(int argc, const char* argv) 

for (int i = argc; i; i--) { 
RecPtr 
p(argv[i]); 


Бьерн Страуструп.
Язык программирования С++ 
 
196 
p->update(); 


На самом деле, тип RecPtr должен определяться как шаблон типа (см. $$8), а тип структуры Record 
будет его параметром. Кроме того, настоящая программа будет содержать обработку ошибок и 
взаимодействие с диском будет организовано не столь примитивно. 
Для обычных указателей операция -> эквивалентна операциям, использующим * и []. Так, если описано 
Y* p; 
то выполняется соотношение 
p->m == (*p).m == p[0].m 
Как всегда, для определенных пользователем операций такие соотношения не гарантируются. Там, где 
все-таки такая эквивалентность требуется, ее можно обеспечить: 
class X { 
Y* 
p; 
public: 
Y* operator->() { return p; } 
Y& operator*() { return *p; } 
Y& operator[](int i) { return p[i]; } 
}; 
Если в вашем классе определено более одной подобной операции, разумно будет обеспечить 
эквивалентность, точно так же, как разумно предусмотреть для простой переменной x некоторого 
класса, в котором есть операции ++, += = и +, чтобы операции ++x и x+=1 были эквивалентны x=x+1. 
Перегрузка -> как и перегрузка [] может играть важную роль для целого класса настоящих программ, а 
не является просто экспериментом ради любопытства. Дело в том, что в программировании понятие 
косвенности является ключевым, а перегрузка -> дает ясный, прямой эффективный способ 
представления этого понятия в программе. Есть другая точка зрения на операцию ->, как на средство 
задать в С++ ограниченный, но полезный вариант понятия делегирования (см. $$12.2.8 и 13.9). 


Достарыңызбен бөлісу:
1   ...   142   143   144   145   146   147   148   149   ...   256




©emirsaba.org 2024
әкімшілігінің қараңыз

    Басты бет