Программирование >>  Обобщенные обратные вызовы 

1 ... 73 74 75 [ 76 ] 77 78 79 ... 84


int compareCconst basic string& str) const; int compare(size type posl, si2e type nl,

const basic string& str) const; int compare(size type posl, size type nl,

const basic string& str,

size type pos2, size type n2) const; int compare(const charT* s) const; int compare(size type posl, size type nl,

const charT* s, size type n2 = npos) const;

Фуу... 103 функций-членов и их шаблонов! Наконец мы можем вынырнуть и вздохнуть полной грудью. Но на этом наши подземные приключения не заканчиваются, и минисерия продолжается.

Резюме

На практике следует разбивать обобшеиные компоненты на части.

Пользуйтесь идиомой один класс (или функция) - одна задача .

Где это возможно - предпочтительно использовать функции, которые не являются членами и друзьями.

Стоило ли перечислять здесь все функции-члены string? Да, поскольку эта информация еше пригодится нам в следующей задаче.



Задача 38. Ослабленная монолитность.

Часть 2: разбор std:: stri ng Сложность: 5

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

Вопрос для новичка

1. Какие из функций-членов std::string обязаны быть членами и почему? Вопрос для профессионала

2. Каким из функций-членов std::string следует быть членами и почему?

3. Покажите, почему функции-члены std::string at, clear, empty и length могут быть реализованы как не члены и не друзья без потери обобщенности, удобства использования и без влияния на остальной интерфейс std::string.

Решение

Членство - быть или не быть

Вспомним совет из последней задачи: там, где это имеет смысл с практической точки зрения, следует разбивать обобщенные компоненты на отдельные части. Пользуйтесь идиомой один класс (или функция) - одна задача . Где это возможно - предпочтительно использовать функции, которые не являются членами и друзьями.

Например, если вы пишете класс string и сделаете поиск, проверку соответствия шаблону и лексический анализ доступными в виде функций-членов, то эта функциональность окажется жестко привязанной к данному классу и не сможет быть использована с последовательностями других типов. Средство, которое служит для той же цели, но состоит из нескольких частей, которые можно использовать независимо друг от друга, зачастую представляет собой лучший дизайн. Применительно к нашему примеру, это означает, что лучше отделить алгоритмы от контейнеров, что в большинстве случаев и сделано в STL.

И я (в [SutterOO] (раздел 5 русского издания)), и Скотт Мейерс (Scott Meyers) (в [MeyersOO]) уже писали ранее о том, почему некоторые функции-не члены являются вполне законной частью интерфейса типа и почему следует предпочитать функции, не являющиеся ни членами, ни друзьями, - помимо прочего, это способствует инкапсуляции. Например, вот как пишет Скотт во вступлении к рассматриваемой статье:

Я начну с главного: если вы пишете функцию, которая может быть реализована либо как член, либо как не друг и не член, то ее надо реализовать именно в виде функции, не являющейся членом. Такое решение увеличивает инкапсуляцию класса. Когда вы думаете об инкапсуляции, вы должны думать о функцияхне членах. - [MeyersOO] Так что когда мы рассматриваем функции, которые будут работать с basic string (или любым другим типом класса), мы хотим сделать их функциями-не членами и не друзьями, если это возможно в рамках разумного. Следовательно, имеется несколько вопросов по поводу функций-членов basi c stri ng.

Всегда делайте их членами, если они обязаны быть таковыми. Какие из операций обязаны быть членами - в соответствии с требованиями языка С~1-+ (например, конструкторы) или по функциональным причинам (например, они



должны быть виртуальными)? Если функции обязаны быть членами, то они, конечно, так и должны быть реализованы.

Если функциям требуется доступ ко внутренним данным, лучше сделать их членами. Какие операции, требующие доступа ко внутренним данным, должны получить его посредством дружбы? Обычно их следует делать функциями-членами класса. Отметим, что имеются редкие исключения, такие как операции, требующие преобразования типов левых аргументов, и операторы наподобие , сигнатуры которых не позволяют ссылке *this быть их первыми параметрами. Несмотря на го, что они могут быть реализованы как функции, не являющиеся друзьями, с использованием функций-членов (возможно, виртуальных), в результате зачастую полуьзется настолько кривое решение, что лучше и естественнее использовать отношение дружбы.

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

Пару слов об эффективности. Для каждой функции следует рассмотреть вопрос, можно ли реализовать ее как функцию-не член и не являющуюся другом так же эффективно, как и в виде функции-члена. Но не является ли это той самой преждевременной оптимизацией, которая не приводит ни к чему хорошему? Нет, ни в коей мере. Основная причина, по которой я рассматриваю вопросы эффективности, - это желание продемонстрировать, какое большое количество функций-членов basi c string можно не хуже реализовать как обычные функции, не являющиеся друзьями класса. В частности, я хочу отбросить все обвинения в том, что такой подход приводит к потенциальной потере эффективности, например, лишая возможности выполнения операции за время, которое от нее требует стандарт. Вторая причина заключается в том, что преждевременность оптимизации библиотеки общего назначения отличается от таковой для прикладной программы. Все необходимые измерения производительности программы можно выполнить на завершающей стадии разработки, в то время как при разработке библиотеки мало что известно о том, как и где она будет использоваться, так что лучше делать все операции максимально эффективными, там, где это не вступает в противоречие с интерфейсом и не вызывает ненужных усложнений. Заметим также, что разработчики библиотек зачастую имеют конкретную информацию из прошлого опыта (например, отчеты пользователей или собственный опыт в предметной области применения библиотеки) о том, какие операции используются в критичных ко времени выполнения фрагментах программ, так что оптимизация выполнясгся не вслепую и не может считаться преждевременной.

Так что не волнуйтесь о преждевременной оптимизации - здесь нет никакой ловушки. Мы всего лишь хотим выяснить, сколько членов basic string можно ничуть не хуже реализовать в виде обычных функций, не являющихся друзьями. Даже если вы и готовы к тому, что многие из них реализуемы как обычные функции, полученные результаты все равно могут вас удивить.

Операции, которые обязаны быть членами

1. Какие из функций-членов std::string обязаны быть членами и почему?

На первом проходе выделим тс операции, которые обязаны быть членами класса. В начале этого списка располагаются совершенно очевидные

конструкторы (6),

деструктор,

операторы присваивания (3),

операторы [] (2).



1 ... 73 74 75 [ 76 ] 77 78 79 ... 84

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика