Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на C / C++ / C++ for real programmers.pdf
Скачиваний:
231
Добавлен:
02.05.2014
Размер:
2.04 Mб
Скачать

144

Конечно, это намного упростило бы жизнь, но назвать эти загадочные ограничения бесполезными нельзя — они дают знатокам С++ хорошую тему для разговоров на семинарах с коктейлями.

Раз уж речь зашла об ограничениях С++, упомяну еще об одном. Взгляните на приведенный выше код класса Foo. Работа некоторых его функций сводится к вызову одной и той же функции для всех переменных класса и в более общем случае — базовых классов. Скажем, Foo::Commit() просто вызывает Commit() для всех переменных. Весь повторяющийся код приходится писать вручную; в языке сильно не хватает макросредств, которые бы позволяли сказать: «Вызвать функцию Commit() для каждой переменной класса». Компилятор знает, как составить список такого рода (и использует его в конструкторах), но вам ни за что не скажет.

Образы указателей

У шабона AutoImage есть одно довольно занятное применение — им можно воспользоваться для создания образов *-указателя. В некоторых ситуациях не хочется создавать лишние копии указываемого объекта только чтобы следить за тем, на что ссылался указатель в прошлой жизни. Собственно, дело обстоит так каждый раз, когда указатель не является ведущим. Указатель также помогает следить за объектами, которые были созданы или уничтожены в процессе транзакции.

AutoImage<Foo*> f;

Теперь вы можете восстановить состояние указателя f в начале транзакции, в том числе и NULL. Тем не менее, существует веский довод в пользу создания специализированного шаблона для *-указателей — необходимость перегрузки оператора ->, чтобы указатель образов можно было использовать в левой части выражений (что-нибудь типа ptr->MemberOfPointer();). Для *-указателей AutoImage похож на глупые указатели, с которыми мы рассправились в начале главы 5. Следующий шаблон больше напоминает обычные умные (но не ведущие!) указатели.

template <class Type> class PtrImage { private:

Type* current; Type* image;

bool have_image; // Истина, если образ существует public:

PtrImage() : current(NULL), image(NULL), have_image(false) {} PtrImage(const PtrImage<Type>& pi)

: current(pi.current), image(NULL), have_image(false) {} PtrImage<Type>& operator=(const PtrImage<Type>& pi)

{

if (this != &pi)

current = pi.current; return *this;

}

PtrImage<Type>& operator=(Type* t) { current = t; return *this; }

operator Type*() { return current; }

Type* operator->() const { return current; } bool operator!() { return current == NULL; } void Snapshot()

{

image = current; have_image = true;

}

void Commit() { image = NULL; have_image = false; }