|
|
Страничка Ильи Жаркова | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Статья
|
|||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||
![]()
|
Некоторые вопросы использования шаблонов И.А. Жарков [email protected] Часто приходится сталкиваться с недопонимаем начинающих программистов, а иногда и опытных, того, как действуют шаблоны классов.Шаблон – это механизм генерирования типов. Из определения шаблона класса и набора аргументов шаблона компилятор генерирует специализацию класса и его используемых методов. Этот процесс называется инстанцированием. Сгенерированный по шаблону класс ведет себя, аналогично обычному классу. В частности, поддерживаются встраиваемые (inline) функции. Каждое инстанцирование класса по шаблону для заданного типа параметров приводит к появлению нового, но практически идентичного класса. Это может вызвать чрезмерное разрастание исполняемого кода и увеличить время компиляции. Создание, вместо шаблона, отдельных специализированных классов может решить только последнюю проблему. Способы борьбы с увеличением сгенерированного кода, которые Б. Страуструп описывает в своих книгах[1][2], во многих случаях помогают. Очень часто начинающие программисты пытаются заменить шаблоны макросами, аргументируя это тем, что макросы эффективнее (ведь компилятор встраивает их в то место, где они используются), что они проще и понятнее. Давайте рассмотрим пример, в котором исследуем объявление класса, работающего с переменной произвольного типа при использовании макроса и шаблона. #define VALUE(valtype, valname)\class __value##valtype##valname\ {\ private:\ valtype m_value;\ public:\ valtype Get() const { return m_value; }\ void Set(valtype val) { m_value=val; }\ };\ __value##valtype##valname valname А теперь то же объявление, но с использованием шаблона. template<class T> class Value{ private: T m_value; public: T Get() const { return m_value; } void Set(T val) { m_value=val; } }; Видно, что разница невелика. Разница невелика даже при объявлении таких объектов и их использовании с типом int: VALUE(int, val1); // создание объекта на основе макросаval1.Set(5); Value<int> val2; // создание объекта на основе шаблона Val2.Set(6); Посмотрим, что произойдет при объявлении массива из десяти таких объектов, работающих с одинаковым типом переменных. Для макроса придется написать десять раз VALUE(int, val1);VALUE(int, val2); ... VALUE(int, val10); и препроцессор создаст десять идентичных классов с именами __valueintvalX (X=1..10) и десять объектов val1…val10 соответствующих типов. Объявление 10 переменных типа int для шаблона будет выглядеть так: Value<int> val[10]; Будет сгенерирован один класс Value<int> и создано 10 объектов этого типа. В случае использования макросов, кроме генерации совершенно излишних определений классов, мы лишаемся возможности корректно сравнивать такие переменные и присваивать их друг другу. В качестве некоторого итога можно сказать, что использовать шаблоны классов необходимо тогда, когда приходится работать с параметризованными типами, т.е. с классами, имеющими в качестве параметра некоторый тип. Иными словами, тогда, когда вам необходим класс, однообразно работающий с различными типами, сделайте такой класс шаблоном.Литература. 1. Страуструп Б. Язык программирования C++. М.: “Невский Диалект” - “Издательство БИНОМ”, 1999. 2. Страуструп Б. Дизайн и эволюция языка C++. М.: ДМК Пресс, 2000. |
|||
![]()
| Хостинг любезно предоставлен ISP "Венс" |
|
Страница была обновленна: 07.11.2002 |
|
Все замечания по содержанию сайта отправляйте по адресу [email protected] |