11.5 Выводы |
Предыдущая Содержание Следующая |
Методы классов применяются к описаниям класса, а не к другим объектам. Необходим по крайней мере один метод класса: new() создаёт объекты из описания класса. Так же как другие методы, методов класса могут компоноваться статически или динамически, но синтаксис ooc допускает только статическую компоновку для методов класса, которые применяются к корневому метаклассу. Поэтому введённый здесь термин метод класса, описывает только метод с динамической компоновкой, который применяется к описанию класса. Так как описаний классов относительно немного, мы можем обеспечить динамическую компоновку для метода класса храня его в самом описании класса, к которому он применяется. У этого есть два преимущества: можно перезаписать методы класса для подкласса не вводя новый метакласс для их хранения; и остаётся неповрежденной наша основная схема, в которой объекты указывают на описания классов, описания классов указывают на свои собственные описания, и последние могут все быть сохранены в struct Class, то есть они все указывают на Class, завершая таким образом иерархию классов чистым способом. Определение new() как метода класса для Object, а не метода со статической компоновкой для Class, позволяет переопределять new() поддеревьям иерархии классов. Это может использоваться для отслеживания выделения памяти, совместного использования памяти, и так далее. ooc не накладывает условий на расширение части данных описания класса. Если бы это сделало, у метода класса могли бы быть локальные данные, применимые к его классу в целом, и мы могли учитывать объекты каждого класса, и так далее. Переменные типа static в файле реализации не совсем то же самое, потому что они существуют для класса и всех его подклассов в одном экземпляре. Есть компромисс между new() и конструктором. Заманчиво выполнять всю работу в new() и оставить конструктора пустым, но тогда переменные, обычно инициализируемые конструктором, могут повредиться, если new() перезаписан. Так же конструктор технически способен к замене различных областей памяти вместо переданной ему от new() — это демонстрировалось в реализации Atom в разделе 2.6 — но надлежащий жизненный цикл этой памяти трудно поддерживать. Как показывает опыт, методы класса, подобные new(), должны только соединить функцию выделения памяти с конструктором и воздержаться от выполнения любых самостоятельных инициализаций. Функции выделения памяти, такие как allocate(), должны проинициализировать указатель описания класса — слишком много может пойти ужасно неправильно, если они этого не сделают. Функции утилизации, таки как delete(), должны позволить деструктору избавиться от ресурсов, накопленных конструктором и жизненным циклом объекта, и передать уже пустую область памяти функции освобождения памяти, подобной free():
Тут соблюдается баланс: allocate() и free() имеют дело с одной и той же областью памяти; по умолчанию new() передаёт её своему конструктору, delete() — своему деструктору; и конструктор, и деструктор имеют дело только с ресурсами, представленными внутри объекта. чтобы вмешаться в поток памяти от allocate() к free(), надо переписать лишь new() и delete().
|
Предыдущая Содержание Следующая |