Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 [ 66 ] 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

Окончание табл. 7.4

Выражение Семантика

S value; Объект класса SmartPtr вызывает функцию Оп-

checkinglmpl .Опоеreference Dereference перед возвращением результата

(value);

const S 1 checking: (value);

const S val ue; Объект класса SmartPtr вызывает функцию On-

lln.i"?" .OnDereference Dereference перед возвращением результата

выполнения константных версий операторов -> и *

В библиотеке Loki определены следующие реализации стратегии Checking.

• Класс AssertCheck, использующий макрос assert для проверки значения перед разыменованием.

• Класс AssertCheckStrickt, использующий макрос assert для проверки значения при инициализации.

• Класс RejectNullStatic, не определяющий функцию onDefault. Следовательно, любая попытка вызвать конструктор по умолчанию в классе SmartPtr приведет к появлению ощибки компиляции.

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

• Класс RejectNull Strict, не позволяющий использовать нулевой указатель в качестве начального значения (генерируя при этом исключительную ситуацию).

• Класс NoCheck, обрабатывающий ощибки в лучщих традициях языков С и С-Ы-, т.е. не проверяющий их совсем.

7.15. Резюме

Поздравляем! Вы добрались до конца самой длинной и обширной главы. Надеемся, ваши усилия были не напрасны. Теперь вы многое знаете об интеллектуальных указателях и вооружены лаконичным и легко настраиваемым шаблонным классом SmartPtr.

Интеллектуальные указатели имитируют синтаксис и семантику простых указателей. Кроме того, они решают многие задачи, выходяище за пределы возможностей простых указателей. Эти задачи могут включать управление владением и проверку значений.

Концепция интеллектуальных указателей намного шире простых указателей. Она может быть обобщена до уровня интеллектуальных ресурсов, например, моникеров (дескрипторов, напоминающих указатели, но имеющих иной синтаксис).

Поскольку интеллектуальные указатели легко автоматизируют процессы, которые практически невозможно реализовать вручную, они стали важным компонентом Современных приложений, от которых требуется особая надежность. Именно от них зависит, будет профамма выполнена успешно или ее работа приведет к утечке ресурсов.

Вот почему разработчики интеллектуальных указателей должны уделять им особое внимание. Со своей стороны профаммисты, использующие интеллектуальные указатели, должны хорошо понимать правила работы с ними и точно им следовать.

Представляя реализацию интеллектуальных указателей, мы уделяли основное внимание вопросу декомпозиции функциональных возможностей на независимые сфатегий, которые можно сопоставлять и смешивать в классе SmartPtr. Возможно поэтому, каждая сфатегия реализует тщательно продуманный интерфейс.



7.16. Краткий обзор класса SmartPtr

• Объявление класса SmartPtr

template

<"

typename т,

template <class> class OwnershipPolicy = RefCounted, class ConversionPolicy = DisallowConversion, template <class> class CheckingPolicy = AssertCheck, template <class> class StoragePolicy = DefaultSPStorage

>

class SmartPtr;

• T - это тип, на который указывает объект класса SmartPtr. Тип т может быть основным или определяться пользователем. Допускается использование типа void.

• Для оставшихся параметров шаблонного класса (OwnershipPolicy, ConversionPolicy, CheckingPolicy и StoragePolicy) можно реализовать свои собственные стратегии или выбирать их по умолчанию, как показано в разделах 7.14.1-7.14.4.

• Шаблонный параметр OwnershipPolicy задает стратегию владения. В качестве такой стратегии можно выбирать классы DeepCopy, RefCounted, RefCountedMT, СОМ-RefCounted, Ref Linked, DestructiveCopy и NoCopy, описанные в разделе 7.14.2.

• Шаблонный параметр ConversionPolicy устанавливает, допускается ли неявное преобразование в базовый тип указателя. По умолчанию неявное преобразование запрешено. В любом случае доступ к объекту осушествляется с помошью вызова функции Getlmpl. В качестве реализации стратегии можно использовать классы Allowconversion и DisallowConversion (раздел 7.14.3).

• Шаблонный параметр CheckingPolicy задает стратегию проверки ошибок. По умолчанию можно использовать классы AssertCheck, Assertcheckstrict, Re-jectNuT\Static, RejectNuT\Strict и NoCheck (раздел 7.14.4).

• Шаблонный параметр StoragePolicy определяет механизм хранения и доступа к объекту. По умолчанию применяется класс Defaul tSPStorage, который, будучи конкретизирован типом т, определяет ссылочный тип т&, сохраняемый тип т*, а также тип т*, возвращаемый оператором ->. В библиотеке Loki определены также сохраняемые типы ArrayStorage, LockedStorage и HeapStorage (раздел 7.14.1).



Фабрики объектов

Для достижения высокого уровня абстракции и модульности в объектно-ориентированных профаммах применяются механизм наследования и виртуальные функции. Полиморфизм, предоставляющий возможность отложить выбор вызываемой функции на период выполнения профаммы, обеспечивает повторное использование бинарного кода и его адаптацию. Система поддержки выполнения профамм автоматически распределяет виртуальные функции по соответствующим объектам производных классов, позволяя описать сложное поведение с помощью полиморфных примитивов.

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

В стационарном режиме у нас уже есть указатели или ссылки на полиморфные объекты, и мы можем вызывать соответствующие функции-члены. Их динамический тип хорощо известен (хотя вызывающий модуль может его не знать). Однако существуют случаи, когда при создании объектов нужна такая же гибкость. Это приводит к парадоксу "виртуальных конструкторов". Виртуальные консфукторы необходимы, когда информация о создаваемом объекте носит динамический характер и не может быть использована в консфукциях языка С+-ь непосредственно.

Чаще всего полиморфные объекты создаются в динамической памяти с помощью оператора new.

class Base { ... };

class Derived : public Base { ... };

class AnotherDerived : public Base { ... };

Создаем объект класса Derived и присваиваем его адрес указателю на класс Base Base* рв = new Derived;

Проблема возникает оттого, что фактический тип Derived указывается непосредственно в вызове оператора new. Между прочим, класс Derived здесь ифает ту же роль, что и явно заданные числовые константы, которых следует избегать. Если нужно создать объект типа AnotherDerived, приходится измешгть соответствующий оператор и изменять тип Derived на AnotherDerived. Сделать этот процесс динамическим невозможно: оператору new можно передавать только типы, точно известные во время компиляции.

В этом заключается принципиальная разница между созданием объектов и вызовом виртуальных функций-членов в языке С+-ь. Виртуальные функции-члены явля-



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 [ 66 ] 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105