6.1 Требования

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

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

(1) все динамические ссылки должны указывать на корректные методы — например, конструктор не должен быть вставлен в неправильное место в описании класса;

(2) нам нужен понятный способ добавления, удаления или изменения порядка динамически скомпонованных методов для суперкласса, гарантируя в тоже время правильное наследование его подклассами;

(3) не должно быть никаких лазеек, таких как отсутствующие динамические связи или не определённые методы;

(4) при наследовании динамически скомпонованного метода реализация суперкласса, от которого мы наследуем, должны оставаться абсолютно неизменной, то есть наследование должно иметь возможность использовать только бинарную информацию;

(5) разные наборы классов должны быть способны иметь разные наборы динамически связанных методов — например, только Point и Circle из главы 4, но не наборы из главы 1 или узлы выражения из главы 3 и 5, могут использовать метод draw().

По большей части этот список показывает, что поддержание динамической компоновки является сложным и подвержено ошибкам — если мы не сможем существенно улучшить ситуацию, то, возможно, создали скорее проблему, чем решение.

До сих пор мы работали с единым списком динамически связанных методов, независимо от того, имело ли это смысл для конкретного класса. Список был определён как struct Class и был подключён везде, где была необходима инициализация динамической компоновки. Благодаря функциям прототипов ANSI-C будет проверять, что имена функций, подобных Point_ctor, соответствуют позициям в описании класса, где они используются как статические инициализаторы. (1) выше является проблемой только если несколько методов имеют интерфейсы совместимого типа или если мы изменим struct Class и сделаем небрежную перекомпиляцию.

Пункт (2), изменение struct Class, звучит как кошмар — надо вручную лезть в реализацию каждого класса для обновления статической инициализацию описания класса и можно легко забыть добавить новый метод в каком-либо классе, создав таким образом проблему (3).

У нас был элегантный способ добавить присвоение в калькулятор в разделе 5.6: мы изменили исходный код и сделали динамически скомпонованные методы для бинарных узлов из раздела 3.6 публичными, чтобы было можно использовать их повторно в качестве инициализаторов для описания Assign, но это явно нарушает требование (4).

Если сохранение единого struct Class звучит уже как вызов, пункт (5) выше предполагает, что мы должны иметь разные версии struct Class для разных наборов классов! Однако, такое требование вполне разумно: каждый класс нуждается в конструкторе и деструкторе; для точек, окружностей и других графических объектов мы добавим средства отрисовки; атомы и строки нуждаются в сравнении; коллекции, подобные наборам, множествам или спискам, имеют методы для добавления, поиска и удаления объектов; и так далее.

 

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