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

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