|
Программирование >> Разработка устойчивых систем
Функция compareO класса string позволяет выполнять гораздо более изощренные и точные сравнения, чем набор внешних операторов. Она существует в нескольких перегруженных версиях для сравнения: двух полных строк; части одной строки с полной строкой; подмножеств двух строк. В следующем примере сравниваются две полные строки. : СОЗ:Compare.срр Применение функций compareO и swapO #1ncl ude <cassert> #1 nclude <str1ng> using namespace std: int mainO { string firstCThis ): string secondCThat ): assert(first.compare(first) == 0): assert(second.compare(second) == 0); Какая из строк лексически больше? assert(first.compare(second) > 0): assert(second.compare(first) < 0): first.swap(second): assert(first.compare(second) < 0): assert(second.compare(first) > 0): } III:- Функция swapO, использованная в примере, меняет местами содержимое своего объекта и аргумента. Чтобы сравнить подмножества символов в одной или обеих строках, добавьте аргументы, определяющие начальную позицию и количество сравниваемых символов. Например, можно воспользоваться следующей перегруженной версией compare(): : C03:Compare2.cpp Использование перегруженной версии compareO #include <cassert> #i nclude <string> using namespace std: int mainO { string firstCThis is a day that will live in infamy ): string second( I dont believe that this is what I signed up for ): Сравнение his is в обеих строках: assert(first.compared. 7. second. 22, 7) == 0): Сравнение his is a с his is w : assert(first.compared, 9, second. 22, 9) < 0): } III:- Bo всех примерах, встречавшихся ранее, при обращении к отдельным символам строк использовался синтаксис индексирования в стиле массивов С. Строки С++ также поддерживают альтернативный вариант: функцию at(). Если все проходит нормально, эти два механизма индексации приводят к одинаковым результатам: : C03:StringIndexing.cpp linclude <cassert> #include <string> using namespace std: int main(){ string s( 1234 ): assert(s[l] == 2): assert(s.at(l) == 2): } III:- И все же между оператором [ ] и функцией at() существует одно важное различие. При попытке обратиться к элементу по индексу, выходящему за границы массива, функция at() великодушно выдает ис1слючение, тогда как обычный синтаксис [ ] приводит к непредсказуемым последствиям: : C03:BadStringIndexing.cpp #include <exception> #inc1ude <iostream> #include <string> using namespace std: int main(){ string s( 1234 ): Функция atO запускает исключение и спасает вас от беды: try { s.at(5): } catch(exception& е) { cerr e.whatO endl: } III:- Добросовестные программисты не пишут неправильные индексы, но если вы захотите воспользоваться преимуществами автоматической проверки индексов, используйте функцию at() вместо оператора [ ], это позволит корректно продолжить работу после ссылок на несуществующие элементы. При запуске этой программы на одном из тестовых компиляторов был получен следующий результат: invalid string position Функция at() запускает объект класса out of range, производный (в конечном счете) от std::exception. Перехватывая этот объект в обработчике, можно предпринять необходимые меры, например вычислить заново неправильный индекс или расширить массив. Индексация с применением операторной функции string::operator[]() не обеспечивает такой защиты и является таким же рискованным делом, как обработка символьных массивов в С. Строки и характеристики символов Знакомясь с программой Find.срр, приведенной ранее в этой главе, трудно удержаться от очевидного вопроса: почему сравнение без учета регистра символов не поддерживается в стандартном классе string? Ответ заставляет по-новому взглянуть на истинную природу строковых объектов C++. Подумайте, а что, собственно, означает регистр символа? В иврите, фарси и японской письменности отсутствуют концепции верхнего и нижнего регистров. По соображениям безопасности комитет по стандартизации С++ рассматривает предложение, согласно которому функция string::operator[] переопределяется идентично string::at(). Ваша реализация может определять все три аргумента шаблона. Поскольку последние два аргумента имеют значения по умолчанию, это объявление будет эквивалентно приведенному в тексте. поэтому для этих языков такая концепция бессмысленна. Конечно, можно создать механизм пометки некоторых языков только верхним или только нижним регистром, это позволит создать обобщенное рещение. Но в ряде языков, поддерживающих концепцию регистра, смысл некоторых символов с диакритическими знаками меняется при изменении регистра (например, седиль в испанском, циркумфлекс во французском или умляут в немецком языке). По этой причине любые схемы с регистровыми символами, претендующие на полноту и законченность, окажутся неимоверно сложными в использовании. Хотя строки С++ обычно интерпретируются как классы, на самом деле это не совсем так. Тип string представляет собой специализацию более общего шаблона bas1c string. Посмотрите, как выглядит объявление string в стандартном заголовочном файле С++: typedef basic string<char> string: Чтобы лучше понять природу класса string, стоит взглянуть на шаблон basic string: temp1ate<c1ass charT. class traits - char traits<charT>. class allocator - anocator<charT> > class basic string; В главе 5 шаблоны будут рассматриваться более подробно (гораздо подробнее, чем в главе 16 первого тома). А пока просто обратите внимание, что тип string создается специализацией шаблона basic string по типу char. Внутри объявления basic string<> следующая строка сообщает, что поведение класса, созданного на базе шаблона basic string, задается классом, созданным на базе шаблона char traits<>: class traits - char traits<charT>. Таким образом, на базе шаблона basic string<> создаются строковые классы, которые помимо char могут работать с другими типами (например, с символами в расширенной кодировке). При этом шаблон char traits<> определяет порядок сортировки в различных кодировках при помощи функций eq() (равно), пе() (не равно) и lt() (меньше). От этих функций зависит работа функций сравнения строк basic string<>. Теперь понятно, почему класс string не содержит функций, не учитывающих регистр символов: это не входит в его задачи. Чтобы изменить способ сравнения строк в классе string, следует предоставить другой шаблон char traits<>, поскольку именно он определяет поведение отдельных функций сравнения символов. На основе этой информации можно создать новую разновидность класса string, игнорирующую регистр символов при сравнениях. Сначала мы должны определить новый шаблон char traits<>, производный от существующего шаблона, который бы игнорировал регистр символов. Затем следует переопределить только те функции, которые бы обеспечивали посимвольное сравнение без учета регистра (кроме трех функций лексического сравнения, о которых упоминалось ранее, также определяется новая реализация функций find() и compare() шаблона char traits). Наконец, мы определяем новую специализацию на базе шаблона basic string<>, но передаем во втором аргументе новый шаблон ichar traits: : C03:ichar traits.h Создание пользовательских классов характеристик символов #ifndef ICHAR TRAITS Н
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |