The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

4.5 Статическая и динамическая компоновка

4.5 Статическая и динамическая компоновка

Предыдущая  Содержание  Следующая V*D*V

Подкласс наследует статически скомпонованные методы своего суперкласса и он может выбрать наследовать или перезаписать динамически скомпонованные методы. Рассмотрим декларации для move() и draw():

 

void move (void * point, int dx, int dy);

void draw (const void * self);

 

Невозможно обнаружить разницу компоновки двух деклараций, хотя реализация move() делает свою работу непосредственно, в то время как draw() лишь селекторная функция, которая прослеживает динамическую компоновку во время выполнения. Единственное отличие состоит в том, что мы декларируем статически скомпонованный метод, подобный move(), как часть интерфейса абстрактного типа данных в Point.h, и декларируем динамически скомпонованный метод, подобный draw(), вместе с интерфейсом управления памятью в new.h, потому что ранее мы решили реализовать селекторную функцию в new.c.

Статическая компоновка более эффективна, поскольку компилятор C может закодировать вызов подпрограммы с помощью прямого адреса, но функция, подобная move(), не может быть перезаписана для подкласса. Динамическая компоновка более гибка за счёт косвенного вызова — мы согласились с накладными расходами на вызов селекторной функции, подобной draw(), проверяя аргументы, выполняя поиск и вызывая соответствующий метод. Можно было бы отказаться от проверки и уменьшить накладные расходы с помощью макроса (* В ANSI-C макросы не раскрываются рекурсивно, поэтому макрос может скрыть функцию с тем же именем.), например

 

#define draw(self) \

    ((* (struct Class **) self) -> draw (self))

 

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

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

В случае возникновения сомнений, вероятно, лучше принять решение о динамической, а не статической компоновке, даже если он менее эффективен. Родовые функции могут служить полезной концептуальной абстракцией и они способствуют уменьшению количества имён функций, которые приходится помнить в ходе проекта. Если после реализации всех необходимых классов обнаружится, что динамически скомпонованный метод никогда не перезаписывается, намного меньше проблем заменить его селектор одной реализацией и даже выбросить его из struct Class, чем расширять описание типа и исправлять все инициализации.

 

Предыдущая  Содержание  Следующая