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



Pdf көрінісі
бет147/256
Дата11.07.2022
өлшемі2,87 Mb.
#37591
1   ...   143   144   145   146   147   148   149   150   ...   256
7.10 Инкремент и декремент 
Если мы додумались до "хитрых указателей", то логично попробовать переопределить операции 
инкремента ++ и декремента -- , чтобы получить для классов те возможности, которые эти операции 
дают для встроенных типов. Такая задача особенно естественна и необходима, если ставится цель 
заменить тип обычных указателей на тип "хитрых указателей", для которого семантика остается 
прежней, но появляются некоторые действия динамического контроля. Пусть есть программа с 
распространенной ошибкой: 
void f1(T a) 
// традиционное использование 


v[200]; 
T* p = &v[10]; 
p--; 
*p = a;
// Приехали: `p' настроен вне массива, 
// и это не обнаружено 
++p; 
*p = a;
// нормально 

Естественно желание заменить указатель p на объект класса CheckedPtrToT, по которому косвенное 
обращение возможно только при условии, что он действительно указывает на объект. Применять 
инкремент и декремент к такому указателю будет можно только в том случае, что указатель настроен на 
объект в границах массива и в результате этих операций получится объект в границах того же массива: 
class CheckedPtrToT { 
// 
... 


Бьерн Страуструп.
Язык программирования С++ 
 
197 
}; 
void f2(T a) 
// вариант с контролем 


v[200]; 
CheckedPtrToT 
p(&v[0],v,200); 
p--; 
*p = a;
// динамическая ошибка: 
// `p' вышел за границы массива 
++p; 
*p = a; // нормально 

Инкремент и декремент являются единственными операциями в С++, которые можно использовать как 
постфиксные и префиксные операции. Следовательно, в определении класса CheckedPtrToT мы 
должны предусмотреть отдельные функции для префиксных и постфиксных операций инкремента и 
декремента: 
class CheckedPtrToT { 
T* 
p; 
T* 
array; 
int 
size; 
public: 
// начальное значение `p' 
// связываем с массивом `a' размера `s' 
CheckedPtrToT(T* p, T* a, int s); 
// начальное значение `p' 
// связываем с одиночным объектом 
CheckedPtrToT(T* 
p); 
T* 
operator++(); 
// 
префиксная 
T* 
operator++(int); 
// 
постфиксная 
T* 
operator--(); 
// 
префиксная 
T* 
operator--(int); 
// 
постфиксная 
T& 
operator*(); 
// 
префиксная 
}; 
Параметр типа int служит указанием, что функция будет вызываться для постфиксной операции. На 
самом деле этот параметр является искусственным и никогда не используется, а служит только для 
различия постфиксной и префиксной операции. Чтобы запомнить, какая версия функции operator++ 
используется как префиксная операция, достаточно помнить, что префиксной является версия без 
искусственного параметра, что верно и для всех других унарных арифметических и логических 
операций. Искусственный параметр используется только для "особых" постфиксных операций ++ и --.
С помощью класса CheckedPtrToT пример можно записать так: 
void f3(T a) 
// вариант с контролем 


v[200]; 
CheckedPtrToT 
p(&v[0],v,200); 
p.operator--(1); 
p.operator*() = a; 
// 
динамическая ошибка: 
// `p' вышел за границы массива 
p.operator++(); 
p.operator*() = a; 
// 
нормально 

В упражнении $$7.14 [19] предлагается завершить определение класса CheckedPtrToT, а другим 
упражнением ($$9.10[2]) является преобразование его в шаблон типа, в котором для сообщений о 
динамических ошибках используются особые ситуации. Примеры использования операций ++ и -- для 
итераций можно найти в $$8.8. 


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


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




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

    Басты бет