Материалы книги получены с http://www.itlibitum.ru/
Вариации
Перед тем как описывать сами алгоритмы уплотнения, давайте рассмотрим другие варианты исходной постановки задачи. Они не оказывают принципиального влияния на архитектуру или алгоритмы, а только на идиомы С++ в их реализации.
Невидимые ведущие указатели
Чтобы не использовать шаблоны дескрипторов и ведущих указателей, можно было организовать множественное наследование ведущих указателей от VoidPtr и гомоморфного базового класса. Иначе говоря, ведущие указатели становятся невидимыми, как объяснялось в предыдущих главах. В игру вступают все механизмы, сопутствующие идиоме невидимых указателей (например, производящие функции).
class Foo {
public:
static Foo* make(); // Возвращает пару указатель-указываемый объект
virtual void Member1() = 0;
// И т.д. для открытого интерфейса
};
// В файле foo.cpp
class FooPtr : public Foo, public VoidPtr {
public:
FooPtr(Foo* foo, size_t size) : VoidPtr(foo, size) {}
virtual ~FooPtr() { delete (Foo*)address; }
virtual void Member1()
{ ((Foo*)address)->Member1(); }
// И т.д. для остальных открытых функций
};
class RealFoo : public Foo { ... };
Foo* Foo::make()
{
return new FooPtr(new RealFoo, sizeof(RealFoo));
}
// В клиентском коде
class Bar {
private:
Foo* foo; // На самом деле невидимый указатель
public:
Bar() : foo(Foo::make()) {}
};
Такое решение улучшает инкапсуляцию применения ведущих указателей. Кроме того, оно позволяет производящим функциям решить, какие экземпляры должны управляться подобным образом, а какие - с помощью обычных невидимых указателей или даже вообще без указателей. Все прекрасно работает, пока вы соблюдаете осторожность и выделяете в VoidPtrPool достаточно места для FooPtr. Помните, что из-за множественного наследования по сравнению с VoidPtr размер увеличивается, по крайней мере, на v-таблицу.
Объекты классов
Возможен и другой вариант - потребовать, чтобы все объекты происходили от общего класса-предка, способного возвратить объект класса для данного объекта или, по крайней мере, размер объекта. В этом случае вам уже не придется хранить в указателе объект экземпляра, поскольку его можно будет получить у объекта класса. Если вы готовы смириться с некоторым насилием в отношении типов в дескрипторах, это также позволит вам избежать шаблонов второго уровня, используемых для главных указателей. Вместо void* в VoidPtr можно будет хранить CommonBase* (где CommonBase - общий базовый класс). Мы избавляемся от переменной size, от необходимости иметь шаблон, производный от VoidPtr, и от виртуального деструктора в VoidPtr, и как следствие - от 4-байтового адреса v-таблицы. С другой стороны, если управляемые объекты уже содержат v-таблицы и не принуждают вас к применению множественного наследования, дополнительных затрат не будет.
Назад Содержание Далее
|