180
Инкапсуляция указателей и указываемых объектов
Одно из величайших преимуществ гомоморфных указателей заключается в том, что указатель вместе с
указываемым объектом можно инкапсулировать в файле .cpp. Взгляните на
только что приведенный
фрагмент. Указатель ничего не добавляет к открытому интерфейсу, представленному в классе
Foo
,
поэтому
клиентам не нужно видеть
PFoo
или производные классы, на которые он ссылается. В
сущности, при достаточной аккуратности можно убедить клиентов, что они работают непосредственно
с указываемым объектом, хотя на самом деле в качестве центрального
звена цепочки присутствует
указатель. Отсюда и термин —
невидимый указатель.
// В файле foo.h
class Foo {
public:
static Foo* make();
// Производящая функция
virtual void do_something() = 0;
virtual void do_something_else() = 0;
};
// В файле foo.cpp
class PFoo : public Foo {
private:
Foo*
foo;
public:
PFoo(Foo* f) : foo(f) {}
virtual void do_something() { foo->do_something(); }
virtual void do_something_else() { foo->do_something_else(); }
};
class Bar : public Foo {
// Все для производного класса
};
Foo* Foo::make()
{
return new PFoo(new Foo);
}
Вставить
PFoo
в существующую программу совсем несложно — при условии, что вы приняли все
меры предосторожности, спроектировали его с расчетом на гомоморфную
иерархию классов и
инкапсулировали производные классы вроде
Bar
. Ведь вы это сделали, не правда ли?
Перед нами
очередной мистический принцип — вы делаете что-то не для того, чтобы извлечь непосредственную
пользу, а для сохранения мировой гармонии. В один прекрасный день вам потребуется вставить умный
указатель, и в гармоничном мире это не вызовет никаких проблем.
Производящие функции
Конечно, производящие функции пригодятся вам каждый раз, когда вы инкапсулируете производные
классы. В приведенном выше фрагменте мы изменили производящую функцию так, чтбы она
создавала два объекта — указатель и указываемое значение.
Обратите внимание: указываемый объект не создается в конструкторе указателя. Для этого существует
веская причина.
Вероятно, нам захочется использовать класс указателя
PFoo
для всех производных
классов
Foo
. Это означает, что некто за пределами класса указателя (производящая функция) решает,
что именно следует создать и спрятать в указателе.
В
предыдущих главах, посвященных умным указателям, основное внимание уделялось шаблонам и
обобщенным классам указателей, соответствующим классам указываемых объектов. С
невидимыми
указателями шаблоны уже не имеют никакого реального значения.