Главная » C++, C++ Builder » Библиотека стандартных шаблонов

0

Borland CBuilder включает в себя, как мы отмечали выше, полный компилятор стандарта ANSI C++. Одним из новых требований к любому компилятору C++, наложенных комитетом ANSI C++, является требование поставки компилятора с реализацией стандартной библиотеки. Это нужно для упрощения переноса так называемого переносимого кода (portable code), например, вспомогательных функций  и функций работы с базами данных, на другой компилятор (другую платформу). Это изменение — одно из самых важных в отношении движения C++ к настоящей переносимости между компиляторами, операционными системами и платформами.

Частью стандартной библиотеки C++ является библиотека стандартных шаблонов (Standard Template Library, STL), которая содержит общие классы, необходимые почти во всех разрабатываемых программах и системах. CBuilder включает полную реализацию  библиотеки Rogue Wave Tools’ STL, которая содержит классы для строк, контейнеров  и  других  изящных вещей. В этой главе мы начинаем исследование STL, сначала вне графической среды CBuilder, а затем как дополнение к разработке приложений, основанных на формах.

Что такое библиотека стандартных шаблонов?

STL — построенная на шаблонах библиотека вспомогательных классов. В ней нет ни графики, ни компонентов, ни чего-либо подобного. Библиотека служит для создания максимального удобства работы с любыми данными любым способом. Библиотека STL предоставляет переносимый класс string (строка),  который позволяет забыть о проблемах переполнения строк в символьных массивах, выделения частей строки и других проблемах, связанных со строками. Класс  string широко распространен в среде CBuilder, так что  вам стоит подумать о его (или подобного ему класса AnsiString, который совместим с VCL) использовании вместо символьных массивов для представления строк в ваших приложениях.

Класс STL string и связанная с ним функциональность являются достаточными причинами, чтобы использовать его в ваших приложениях или как минимум изучить его, но класс string является только небольшой частичкой мощи STL. В дополнение к строкам, STL также  предоставляет полную реализацию массивов (которые на жаргоне STL  называются  векторами,  vectors), связанных списков (и одно-, и двунаправленных), очередей (queues), таблиц (maps, что-то типа словаря) и других стандартных структур данных.

Все классы STL представляют из себя шаблоны . Если вы некоторое время работали с C++, то вы вероятно знаете, что шаблоны — это очень умные макросы, с  которыми  умет  работать компилятор. Чтобы понять, что такое  шаблоны, представьте себе  следующую  ситуацию.  У  вас есть класс массив (array), который хранит целые числа. Он знает, как выделить память под целое, сохранить его в памяти, получить его из памяти по индексу в массиве и найти заданное целое в массиве. Этот класс замечательно подходит для хранения ваших целых чисел и вы используете его некоторое время, но теперь вам нужно кроме целых хранить еще и вещественные числа с плавающей точкой. У вас есть два варианта.  Во-первых,  вы  можете  скопировать  изначальный класс для массива целых и заменить в нем все ключевые слова int (целое) на double (вещественное с двойной точностью). Или вы можете разработать некую фантастическую систему, которая будет преобразовывать вещественные в целые, теряя при этом всю их точность (чем, я уверен, неслыханно обрадуете банковских служащих).

Вместо болезненного клонирования всего класса для нового типа данных, не проще ли было бы если бы можно было заставить компилятор подставлять ключевое слово double всюду, где в вашем классе встретится int? Ну, может быть, не всюду — и вот в этом основное препятствие. Давайте посмотрим на описание класса (часть нашего мифического класса массив целых):

class IntegerArray

{

int *pArrayOfInts; int nNumberOfInts; public:

IntegerArray (int nNumberOfInts);

~IntegerArray(void);

void Add (int nIntToAdd );

void Remove (int nIntToRemove ); int Find (int nIntToFind ); // Возврат:

// индекс найденного числа

int GetAt (int nIndex );

void SetAt  (int nIndex, int nIntegerToAdd);

};

Теперь, предположим, вам нужно хранить массив вещественных чисел с плавающей точкой (floating-point). Вы, вероятно, просто скопировали бы предыдущий заголовок и изменили его так, чтобы поддерживать вещественные числа (двойной точности, double). В этом случае у вас, вероятно, получился бы еще блок кода, типа такого:

class DoubleArray

{

double *pArrayOfDoubles; int nNumberOfDoubles; public:

DoubleArray (int nNumberOfDoubles);

~DoubleArray(void);

void Add (double dDoubleToAdd );

void Remove (double dDoubleToRemove );

int Find (double dDoubleToFind ); // Возврат: индекс

// найденного числа

int GetAt (int nIndex );

void SetAt (int nIndex, double dDoubleToAdd);

};

Конечно, как только вы реализовали версии класса для целых и вещественных, вам тут же потребуется класс, который хранил бы строки. Потом вам потребуется  еще  один  класс, работающий с каким-нибудь объектом, который вы сохраняете в вашем приложении. Этот список может продолжаться бесконечно (пока вы не сойдете с ума, разрабатывая классы).

Не было бы лучше, если бы мы могли написать класс один раз и затем все остальные классы генерировались из какой-нибудь базовой копии? Когда вы делаете копию автомобиля или еще чего-нибудь, то базовая конструкция часто называется шаблоном (template). Так  что  это подходящий термин для базового класса, который содержит инструкции, позволяющие конструировать различные классы на  его основе. В предыдущем примере мы бы тогда создали один класс, называемый Array (массив), который бы работал с одним параметром (параметром шаблона), который представляет из себя тип данных, с которым мы хотим работать. Тогда мы бы написали шаблонный класс так:

template <class _Type> class Array

{

_Type *pArrayOfType; int nNuberOfType; public:

Array (int nNumberOfType);

~Array (void);

void Add (_Type tTypeObject ); void Remove (_Type tTypeObject );

int Find (_Type tTypeObject ); // Возвращает номер

// найденного объекта

_Type GetAt (int nIndex );

void SetAt (int nIndex, _Type tTypeObject);

};

Когда вам захотелось бы создать новый класс, использующий этот как  шаблон,  то  вы использовали бы аргумент, как при вызове функции. Например, для создания массива целых, вы бы написали:

Array<int> intArray;

Для массива вещественных чисел это выглядело бы так:

Array<double>  doubleArray;

И, наконец, массив некоторого произвольного типа (например, класса string) выглядел бы так:

Array<string> stringArray;

Что-то такого типа было бы замечательно, не правда ли? Вероятно, вам никогда бы не понадобилось писать другой класс Array. Ну, это в точности и есть функциональность, предоставляемая STL. Эта библиотека содержит шаблонные версии всех стандартных структур данных, нужных большинству приложений. Для использования массива целых, например,  вам нужно использовать класс vector. Для создания таблички, сопоставляющей строке целое, используется класс map и так далее.

Зачем нужна библиотека стандартных шаблонов?

Весь этот сгенерированный код, конечно, является хорошим стимулом для использования STL, но есть более убедительные аргументы. Когда вы пишете вспомогательный код,  например управление файлами, или базами данных, или  просто  классы  для  бизнес-приложения,  вы частенько найдете, что вам нужно поддерживать разные платформы. Код должен работать в Windows 95 под C++Builder, также необходимо использовать объекты в управляющих элементах ActiveX для Internet и Unix-приложений. Если вы будете использовать собственные структуры данных, такие как в OWL или MFC, то вам очень не повезет, если вам придется переходить на другие компиляторы или операционные системы. Используя библиотеку STL, которая доступна в исходниках (бесплатно) от компании Hewlett Packard (откуда и пошла библиотека STL),  вы можете быть уверены, что этот код будет работать на всех платформах, которые вам нужны. Процедура, которую вы написали для своего любимого Amiga 2000 (да, у меня  действительно такой есть, и да, он все еще работает), будет работать в неизменном виде на Pentium II, который вы вчера купили. Если это недостаточно мощный стимул  для использования STL, то примите во внимание следующее. Компания Borland была так поражена мощью и гибкостью STL, что она не предоставляет никаких других компонентов в VCL для обработки массивов, связанных списков и т.д. Вы можете использовать STL напрямую в компонентах VCL. Короче, не существует причин, почему бы не использовать библиотеку шаблонов STL в ваших приложениях.

Источник: Теллес М. – Borland C++ Builder. Библиотека программиста – 1998

По теме:

  • Комментарии