Анимация
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

бой класс часто можно считать собственным суперклассом. Если проверку нужно ужесточить, можно написать следующий код.

#define SUPERSUBCLASS STRICT(T, и) \ (SUPERSUBCLASS(T, U) && \ !(Conversion<const т, const и>::sameType)

Зачем в этом фрагменте кода столько модификаторов const? Причина состоит в том, что проверка не должна завершаться неудачей из-за проблем, связанных с этими модификаторами. Если шаблонный код применяет модификатор const дважды (к типу, который уже является константным), второй модификатор игнорируется. Короче говоря, модификатор const в макросе SUPERSUBCLASS применяется в целях безопасности.

Почему макрос назван SUPERSUBCLASS, а не base OF или INHERITS? По одной очень важной причине. Первоначально в библиотеке Loki этот макрос назывался INHERITS. Однако при использовании выражения INHERITS (т, и) каждый раз возникал вопрос, что именно проверяется: то, что класс т является производным от класса и, или наоборот? Очевидно, что выражение SUPERSUBCLASS(т, U) таких сомнений не вызывает, поскольку в его названии первая часть (SUPER) относится к первому параметру т, а вторая (SUB) - ко второму параметру и.

2.8. Оболочка вокруг класса typejnfo

в стандарте язьпса С++ предусмотрен класс std: :type info, позволяющий исследовать типы объектов в ходе вьтолнения программы. Обычно класс type info применяется в сочетании с оператором typeid, возвращающим ссылку на объект класса type info.

void Fun(Base* pObj) {

Сравнивает два объекта типа type info с типами *pObj и Derived, соответственно if (typeid(*pObj) == typeid(Derived) {

... ага, на самом-то деле указатель pObj ссылается на объект класса Derived ...

} ""

Оператор typeid возвращает ссылку на объект класса type info. Кроме операторов сравнения operator== и operator !=, класс type info содержит еще две функции.

• Функция-член name возвращает текстуальное представление типа в форме переменной типа const char*. Стандартного способа преобразовывать имена классов в строки нет. Поэтому не следует ожидать, что значением выражения typeid (widget) будет строка "widget". Вполне приемлемо (хотя и не слишком хорошо), если реализация функции-члена type info: :name возвратит для всех типов пустую строку.

• Функция-член before устанавливает между объектами типа type info отношение порядка. Используя эту функцию, можно индексировать объекты класса type info.

К сожалению, полезные свойства класса type info реализованы так, что их трудно эксплуатировать. В классе type info не предусмотрены конструктор копирования и оператор присваивания, что не позволяет хранить в памяти объекты этого типа. Однако можно хранить указатели на объекты типа type info. Объекты, возвращаемые оператором



typeid, хранятся в статической памяти, поэтому беспокоиться о времени их жизни не стоит. Вместо этого следует обеспечить идентичность указателей (pointer identity).

Стандарт языка С++ не гарантирует, что при каждом вызове, например, оператора typeid ("int), возвращается ссылка на один и тот же объект класса type info. Следовательно, сравнить указатели на объекты класса type info невозможно. Хранить указатели на объекты этого типа и сравнивать их между собой нужно с помощью функции type info: :operator==, которая применяется к разыменованным указателям.

При необходимости рассортировать объекты класса type i nfо снова нужно сохранить указатели на них, но на этот раз использовать функцию-член before. Следовательно, для того чтобы применить упорядоченные контейнеры из библиотеки щаблонов STL, нужно написать небольшой функтор (functor) и поработать с указателями.

Все это довольно неудобно. Для того чтобы преодолеть эти трудности, создадим вокруг Kjiacca type i nf о интерфейсный класс (wrapper class), в котором хранится указатель на объект типа type i nf о и предусмотрено следующее.

• Все функции-члены класса type i nf о.

• Семантика значений (открытый конструктор копирования и оператор присваивания).

• Операторы сравнения operator< и operator==.

В библиотеке Loki определен интерфейсный класс Typelnfo, в котором реализована описанная выше оболочка класса type i nf о. Вот его краткий обзор.

class Typelnfo {

public:

Конструкторы/деструкторы Typeinfo(); Необходим для контейнеров Typelnfo(const std::type info&); Typelnfo(const Typeinfo&); Typelnfo& operator==(const TypeinfoA); функции сравнения bool before(const Typelnfo&) const; const char* nameO const; private:

const std::type info* plnfo ;

Операторы сравнения

bool operator==(const Typelnfo&, const TypelnfoA); bool operator!=(const Typelnfo&, const TypeInfo&); bool operator<(const TypeinfoA, const Typeinfo&); bool operator<=(const Typeinfo&, const Typeinfo&); bool operator>(const TypelnfoA, const TypelnfoA); bool operator>=(const Typelnfo&, const Typeinfo&);

Благодаря конструктору преобразования (conversion constructor), получающему в качестве параметра объект класса std: : type i nfo, можно непосредственно сравнивать объекты типов Typelnfo и std: :type info, как показано ниже.

void Fun(Base* pObj) {

Typelnfo info = typeid(Derived);

if (typeid(*pObj) == info)

... Указатель pBase действительно указывает 60 Часть I. Методы



на объект класса Derived ...

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

2.9. Классы NullType и EmptyType

в библиотеке Loki определены два очень простых типа: NullType и EmptyType. Их можно использовать для идентификации более широких типов.

Класс NullType служит в качестве нулевого маркера типов (null marker), class NullTypeO;

Обычно объекты этого класса не создаются. Его единственное предназначение - обозначить типы, не представляющие интереса. В разделе 2.10 класс NullType используется в ситуациях, когда тип имеет синтаксический смысл, но не имеет семантического. (Например: "На объекты какого типа указывает переменная типа int?".) Кроме того, списки типов, описанные в главе 3, используют класс NullType в качестве маркера конца списка и для возврата сообщения "тип не найден".

Второй вспомогательный тип - класс EmptyType. Как и следовало ожидать, его определение имеет следующий вид.

struct EmptyType {};

Этот тип можно использовать в качестве базового класса, а также для передачи значений типа EmptyType. Кроме того, его можно применять в шаблонах в качестве типа, заданного по умолчанию ("не важно какой").

2.10. Характеристики типов

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

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

Допустим, что мы реализуем алгоритм копирования.

template <typename Init, typename Outit>

Outit CopyCinit first, init last, Outit result)

for (; first != last; ++first, ++result) result = *first;



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