Анимация
JavaScript
|
Главная Библионтека basi c stri nq<charT, trai ts, Allocator>& operator+= (basic string<charT, traits, A!locator>& s, const chart* p ) { return s.appendC p ); tempiate<class charx, class traits, class Allocator> basic strinq<charX, traits, AllocatorxS operator+=(basic string<charx, traits, Allocator>& s, charx с ) { return s.append( 1, с ); Что же позволяет объединить все члены этой группы, сделав их обычными функциями, которые не являются друзьями класса? Это insert; следовательно, именно insert имеет смысл сделать членом класса, выполняющим основную работу и инкапсулирующим доступ ко внутренним данным класса, необходимый для добавления к строке чего-либо. Такое решение позволит сосредоточить обращение ко внутренним данным в одной функции, не "размазывая" его по дюжине функций. insert б) insert. Тем, кому кажется, что шести версий assign и шести версий append многовато для одного класса, рекомендую запастись валерьянкой: сейчас мы рассмотрим восемь версий insert. Я уже предлагал использовать в качестве функции-члена трехпараметрическую версию insert, а сейчас я поясню, почему. Во-первых, как упоминалось ранее, insert - более общая операция по сравнению с append, так что наличие функции-члена insert позволяет сделать все операции append обычными функциями, которые не являются друзьями класса. Если мы не сделаем функцией-членом хотя бы одну из функций insert, то нам придется сделать членом как минимум одну из функций append, так что я выбрал для "членства" более фундаментальную и гибкую операцию. Однако у нас восемь функций insert. Какую из них (или какие) сделать членом класса? Пять из восьми функций insert непосредственно определены посредством функции insert с тремя параметрами, да и остальные версии вполне можно эффективно реализовать при помощи этой трехпараметрической функции. Поэтому функцией-членом мы делаем именно ее, а все остальные могут быть обычными функциями, не являющимися друзьями класса. Небольшой перерыв Для тех из вас, кто думает, что уж восемь версий insert - это перебор, сообщаем - нет, это только разминка. Потерпите еще немного, и мы рассмотрим десять версий функции replace. Но, чтобы пощадить ваши нервы, мы сделаем небольшой перерыв и в начале следующей задачи рассмотрим случай попроще... Задача 40. Ослабленная монолитность. Часть 4: новый std:: stri ng Сложность: 6 в этой задаче мы наконец полностью разберемся с классом std: .-string и посмотрим, как выглядит строковый класс минимального размера. Вопрос для новичка 1. Может ли string::erase быть функцией-не членом? Обоснуйте свой ответ. Вопрос для профессионала 2. Проанализируйте оставшиеся функции-члены std: :string и покажите, могут ли они быть сделаны обычными функциями-ие членами. Обоснуйте ваш ответ. а) replace б) сору и substr в) compare г) Семейство fi nd (find, find * и rfind) Решение Прочие операции, которые могут не быть членами Нам осталось рассмотреть только несколько функций, и, как вы увидите, все они могут быть реализованы как обычные функции, не являющиеся друзьями класса. • erase (2 - все версии, кроме "iter, iter") • replace (8 - все версии, кроме "iter, iter, num, char" и шаблонных) • copy • substr • compare (5) • fi nd (4) • rfi nd (4) • fi nd fi rst of (4) • find last of (4) • find first not of (4) • f i nd l ast nоt of (4) Небольшой перерыв на кофе 1. Может ли string::erase быть функцией-не членом? Обоснуйте свой ответ. После того как мы рассмотрели и разобрались с тремя десятками версий функций assign, append, insert и replace, для вас будет большим облегчением услышать, что есть только три версии функции erase. После всего, с чем мы имели дело, это занятие - разминка на время перерыва для того, чтобы выпить чашечку кофе... Тройка функций-членов erase малоинтересна. Как миниму.м одна из этих функций должна быть членом (или другом), другого пути эффективной реализации этих функций с использованием прочих уже рассмотренных функций-членов нет. Есть два "семейства" функций erase. eraseC pos, length ) basi c string& erase(size type pos = 0, size. type n = npos); erase( iten, ... ) iterator erase(iterator position); iterator erase(iterator first, iterator last); Сразу обратим внимание на различия возвращаемых этими семействами типов: первая версия возвращает ссылку на строку, а остальные - итератор, указывающий на позицию, следующую непосредственно за удаленным символом или диапазоном символов. Далее заметим, что различны и типы аргументов этих двух семейств. Первая версия в качестве аргументов получает смещение и длину, в то время как вторая - итератор или диапазон, определяемый итераторами; к счастью, легко выполнить как преобразование итераторов в смешения (pos = iter - beginO), так и смещений в итераторы (iter = begiп() + pos). (Кстати: стандарт этого не требует, но разработчик вполне может реализовать basi c st ring так, что объекты этого типа будут хранить свои данные в памяти в непрерыв-ном массиве charx. Если это так, то очевидно, что преобразование итераторов в смещения и наоборот не приведут к каким-либо накладным расходам. Хочу, однако, заметить, что даже при использовании схемы сегментированного хранения строки можно разработать очень эффективный способ преобразования итераторов в смещения и обратно, используя только открытые интерфейсы контейнеров и итераторов. Это небольшое отступление от основной темы сделано исключительно для полноты изложения.) Все сказанное позволяет нам выразить первые две версии функции через третью. tempiate<class charx, class traits, class Allocater> basic string<charT, traits, Allocator>& erase(basic string<charx, traits, Allocator>& s, typename Allocator::size.type pos = 0, typename Allocator::size type n = basic string<charx, traits, Allocator>::npos ) if( pos > S.sizeO ) throw out of range( "yes, we have no bananas" ); typename basic string<charX,traits,Al1ocator>::iterator first = s.begin()+pos, last = n==basic„string<charx,traits,Allocator>::npos ? s.endO : first + min( n, s.sizeO - pos ); if( fi rst != last ) s.erase( fi rst, last ); return s; tempiate<class charx, class traits, class Allocator> typename basic strinq<charX, traits, АПосаСог>::iterator erase(basic string<cnarx, traits, Allocator>& s, typename basic string<charx, traits, Allocator>::iterator position ) return s.erase( position, position+1 ); Ну что же, думаю, кофе к этому времени выпит?... replace 2. Проанализируйте оставшиеся функции-члены std::string и покажите, могут ли они быть сделаны обычными функциями-не членами. Обоснуйте ваш ответ. а) replace 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 |