А. Александреску - Современное проектирование на C++ (1119444), страница 14
Текст из файла (страница 14)
Достаточно использовать фиктивную функцию, возврашаюшую объект класса т, (Еше раз напомним, что чудесная функция 51хеоГ на самом леле не вычисляет выражения.) Тогла и компилятор будет сыт, и программа цела. т макетО; // ие реализуется сопзт Ьоо1 сопчвх)зта = 51хеог(тезт(макето)) == з(гео((5аа11); (Кстати, обратите внимание, как остроумно устроена эта проверка — функции макет и тезт не только не имеют никаких параметров, но и не сушествуют вообше!) Итак, все летали этого механизма работают хорошо, и настало время упаковать их в шаблонный класс, который скрывает подробности, связанные с процессом вывода классов. оставляя на поверхности лишь окончательный результат. теар1ате <с1азз т, с1азз ц> с1азз сопчегз1оп ( туреоеГ сйаг 5аа11; с1азз в)д ( сйаг дцаау(2]; зтат)с 5аа11 тезт(ц)„ зтатбс в19 тезт(...); Глава 2. Приемы программирования 57 зтат)с т маЛет(); риЫзс: епиш ( ех)зтз = з)аеот(техт(маЛет0)) == ззгеоЕ(5ша11) Теперь можно испытать шаблонный класс сопчега1оп.
1пт шазпо изтпй пашезрасе зтб; спит сс СОПЧЕГЗЗОП<ООиЫЕ, ЗПТ>::ЕХЗЗТЗ <с ' <с СОПЧЕГаЗОП<СЛаГ, СЛаГ<>::ЕХ)вта « ' « сопчеагзоп<5)хе т, честог<зпт»::ехззтв « Эта небольшая программа выводит на печать строку "1 О О". Обратите внимание на то, что, хотя класс зтб::честог реализует конструктор, получающий параметр типа азхе Т, программа возвращает число О, поскольку это явный конструктор.
В классе можно реализовать еше одну константу сопчегззоп::вашетуре, принимающую значение Тгие, если классы т и 0 представляют собой один и тот же тип. тешр1ате <с1ааа т, с1ааз О> с1ааа Сопчегззоп ( хах и раньше ... епиш ( зашетуре та1зе ); Реализуем константу аашетуре с помощью частичной специализации шаблонного класса Сопчегззоп. тешр1ате <с1ааа т> с1азз сопчегззоп<Т, Т> риЫ1с: епиш ( ехзасз = 1, аашетуре = 1 ); О) ~ сопят т*>::ехззтз 84 ~ сопзт чеза*>::зашетуре); Макрос 50Рея50всьА55(т, О) вычисляет значение тгие, если класс 0 является производным от класса т, или если классы т и 0 представляют собой один и тот же тип.
Этот макрос выполняет свою работу, распознавая конвертируемость указателей типа сопят О* в указатели сопят т*. Возможны только три случая, в которых указатели типа сопят О* неявно преобразовываются в указатели сопят т». К Классы т и 0 представляют собой один и тот же тип. 2. Класс т является единственным открытым базовым классом для класса О. 3. Класс т представляет собой тип чо)6.
Последнее исключается при второй проверке. На практике бывает полезно считать первый вариант (классы т и 0 представляют собой один и тот же тип) вырожденным случаем отношения "является" ("Ь-а"), поскольку с практической точки зрения лю- Часть!. Методы Итак, вернемся к исходной жить наследование, Виетзпе 50РЕя50ВСЬА55(Т, (Сопчегззоп<сопас О*, !Сопчегзз'оп<сопят Т*, задаче. С помощью класса Сопчегззоп легко обнару- бой класс часто можно считать собственным суперклассом. Если проверку нужно ужесточить, можно написать следующий код. «беНпе 50Рея50всьл55 5тятст(т, О) ~ (50Рек50всьл55(т, О) бб ~ !(сопчегэ1оп<сопзс т, сопзс О>:тааметуре) Зачем в этом фрагменте кода столько модификаторов сопзс? Причина состоит в том, что проверка не должна завершаться неудачей из-за проблем, связанных с этими модификаторами.
Если шаблонный кол применяет модификатор сопзс дважды (к типу, который уже является константным), второй модификатор игнорируется. Короче говоря, модификатор сопзС в макросе 50РЕЯ50ВССА55 применяется в целях безопасности. Почему макрос назван 50Рея50вссл55, а не вдве ОР или 1мнентт5? По одной очень важной причине. Первоначально в библиотеке (.ОЫ этот макрос назывался 1мНЕЯ1Т5. Олнако при использовании выражения 1ННЕЯ1Т5(Т, О) кажлый раз возникал вопрос, что именно проверяется: то, что класс т является производным от класса О, или наоборот? Очевидно, что выражение 50Рея50вссл55(т, О) таких сомнений не вызывает, поскольку в его названии первая часть (50Рея) относится к первому параметру т, а вторая (50в) — ко второму параметру О.
2.8. Оболочка вокруг класса 1уре )п1о В станларте языка С++ предусмотрен класс зсб:: суре 1пЕо, позволяющий исследовать типы обьектов в ходе выполнения программы. Обычно класс туре 1пУО применяется в сочетании с оператором туре(д, возвращающим ссылку на объект класса суре 1пУо. чо1д Рцп(вазе» рОЬ)) // Сравнивает два объекта типа Суре 1п(о с типами // »рОЬ) и Оег10ед, соответственно 1т (суре1т)(»рОЬ)) = суре1д(оег1нет1) ( ага, иа самом-то деле указатель рОЬ) ссылается иа объект класса Оег1мед Оператор суре10 возвращает ссылку на объект класса суре 1пЕо.
Кроме операторов сравнения орегасог=- и орегасог! =, класс суре 1пбо содержит еше две функции. ° Функция-член паве возвращает текстуальное представление типа в форме переменной типа сооэс сЬаг». Станлартното способа преобразовывать имена классов в строки нет. Поэтому не слелует ожидать, что значением выражения суре1д(и1дйес) будет строка «и1ддес". Вполне приемлемо (хотя и не слишком хорошо), если реализация функции-члена суре 1п1о::паве возвратит для всех типов пустуто строку. «Функция-член Ье(оге устанавливает между объектами типа суре 1пЕО отношение порядка. Используя эту функцию, можно инлексировать объекты класса суре 1пФо.
К сожапению, полезные свойства класса суре 1пУо реализованы так, что их трудно эксплуатировать. В классе суре 1пЕо не предусмотрены конструктор копирования и оператор присваивания, что не позволяет хранип в памяти объекты этого типа. Однако можно хранить указатлела на объекты типа суре 1пто. Обьекты, возвращаемые оператором 59 Глава 2.
Приемы программирования суре1д, хранятся в статической памяти, поэтому беспокоиться о времени их жизни не с~опт. Вместо этого следует обеспечить идеитичлосшь указателей (ро!псег !дспс!су). Стандарт языка С++ не гарантирует, что при каждом вызове, например, оператора сурезд(з пс), возвращается ссылка на один и тот же объект класса суре зобо. Следовательно, сравнить указатели на объекты класса суре 1пбо невозможно. Хранить указатели на объекты этого типа и сравнивать их между собой нужно с помощью функции суре зобо::орегасог==, которая применяется к разыменованным указателям. При необходимости рассортировать объекты класса суре з ото снова нужно сохранить указатели на них, но на этот раз использовать функнию-член ЬеТоге.
Следовательно, для того чтобы применить упорядоченные контейнеры из библиотеки шаблонов БТ), нужно написать небольшой функтор (1ипссог) и поработать с указателями. Все это довольно неудобно. Для того чтобы преодолеть эти трудности, создадим вокруг класса суре )пТо интерфейсный класс (зчгаррег с!аяя), в котором хранится указатель на объект типа суре з пго и предусмотрено следующее. ° Все функдии-члены класса суре з ибо. ° Семантика значений (открытый конструктор копирования и оператор присваивания). ° Операторы сравнения орегасог< и орегасог==.
В библиотеке сои определен интерфейсный класс туретпУо, в котором реализована описанная выше оболочка класса суре з про. Вот его краткий обзор. с1аяя туретпУо риЬ)зс: // Конструкторы/деструкторы туретптоО; // необходим для контейнеров туретп1о(сопяс ясд:: суре 1п1ой); туретпбо(сопяс туреспУой); туреспбой орегасог==(сопяс туретп1ой); // еункции сравнения Ьоо1 Ьебоге(сопят туретпбой) сопяс; сопяс спасе паве() сопяс; рг)часе: сопяс ясд::суре япСо* рспУо ) // операторы сравнения Ьоо1 орегасог==(сопят туреспФой, сопяс туреспФой)! Ьоо1 орегасог!=(сопят туреспФой, сопяс туретп1ой); Ьоо1 орегасог<(сопят туреспФой, сопят туретпХой); Ьоо1 орегасог<=(сопяс туресп1ой, сопят туресптой)! Ьоо1 орегасог>(сопят туретпбой, сопяс туретпУой)! Ьоо1 орегасог>=(сопяс туреспФой, сопяс туретпбой); Благодаря конструктору преобразования (сопмегяоп сопмгис[ог), получающему в качестве параметра объект класса ясд::суре 1пУо, можно непосредственно сравнивать объекты типов туреспФо и ясд:: суре )пто, как показано ниже.
чо1д ьвп(вазе* роЬ)) туретин з'пСо = суре)д(оег)мед); 1Ф (суре1д(ероЬ)) == зобо) указатель рваяе действительно указывает Часть Ь Методы на объект класса оегзнед ) Способность копировать и сравнивать между собой объекты класса туретпФо важна во многих ситуациях. Фабрики клонирования, описанные в главе 8, и механизм двойной диспетчеризации, рассмотренный в главе 11, достаточно ярко иллюстрируют этот факт. 2.9. Классы йиПТуре и ЕГпртуТуре В библиотеке Ео г1 определены два очень простых типа: нц11туре и впртутуре. Их можно использовать для идентификации более широких типов. Класс но11туре служит в качестве нулевого маркера типов (пцй гпаг)гег).