Основы объектно-ориентированного проектирования

         

Эмулирующие классы


Описанная техника будет работать в определенных пределах. Ее даже можно расширить для эмуляции наследования.

Но она неприменима к серьезным разработкам, что иллюстрируется на рис. 16.1. Каждый экземпляр любого класса должен физически содержать ссылки на все применимые к нему подпрограммы. Это приведет к существенным потерям памяти, особенно при наследовании.

Для снижения потерь заметим, что подпрограммы одинаковы для всех экземпляров класса. Поэтому для каждого класса можно ввести структуру данных периода выполнения, дескриптор класса, содержащий ссылки на подпрограммы. Его можно реализовать как связный список или массив. Требования к пространству значительно уменьшаются: вместо n*m указателей можно иметь их n+m, где n - число подпрограмм, а m - число объектов, как показано на рис. 16.2.


Рис. 16.2.  Объекты C, разделяющие дескриптор класса

Это приводит к незначительным временным потерям, но экономия пространства и простота стоят этого.

В этой технике нет секрета. Именно она сделала С полезным в качестве средства реализации для компиляторов ОО-языков, начиная с Objective-C и C++ в начале 80-х. Способность использовать указатели функций, в сочетании с идеей группирования этих указателей в дескриптор класса, разделяемый произвольным числом экземпляров, служит первым шагом к реализации ОО-техники.

Конечно, это только первый шаг, и нужно еще найти способы реализации наследования (особенно непросто множественное наследование), универсальности, исключений, утверждений и динамического связывания. Объяснения потребовали бы отдельной книги. Отметим лишь одно важное свойство, выводимое из всего, что мы видели до сих пор. Реализация динамического связывания требует доступа к типу каждого объекта во время выполнения для нахождения нужного варианта компонента f в динамически связываемом вызове x.f (...) (написанном здесь в ОО-нотации). Другими словами: в дополнение к официальным полям объекту необходимо дополнительное внутреннее поле, порождаемое компилятором и указывающее на тип объекта. Описанный подход показывает возможную реализацию такого поля - как указателя на дескриптор класса. По этой причине на рис. 16.2 для такого поля используется ярлык type.



Содержание раздела