Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Книга C++.doc
Скачиваний:
24
Добавлен:
10.11.2019
Размер:
2.48 Mб
Скачать

Переопределение шаблонов функций

Каждая версия функции, генерируемая с помощью шаблона, содержит одинаковый базовый код. Единственным изменяемым свойством функции будут значение параметра (или параметров) типа. Однако для отдельного параметра (или параметров) типа можно обеспечить специальную обработку. Для этого определяется обычная функция языка С++ с тем же именем, что и шаблон функции, но использующая уже имеющиеся типы данных, а не параметры типов. Обычная функция переопределяет шаблон. Т.е., если компилятор обнаруживает, что типы переданных параметров соответствуют спецификации обычной функции, то он вызовет ее, а не создаст функцию по шаблону.

Шаблоны классов

Вы уже знаете о создателе С++ Бьярне Страуструпе (Bjarne Stroustrup) и его фундаментальном труде "The C++ Programming Language". Примичателен следующий факт: все главы этой книги начинаются с цитаты. Что касется шаблонов, то Страуструп использовал следующую: "На этом месте Ваша цитата". Таким образом, после ознакомления с этим материалом, Вы сможете сами подобрать цитату к этому разделу.

В этом разделе мы познакомимся с обобщенными (иногда, Вы можете втсретить определение параметризованными) классами. И начнем, пожалуй, с обозрения недалекого прошлого.

Работу над определением шаблонов в языке С++ Страуструп ведет с 1986 года. В своей книге "The Design and Evolution of C++" Страуструп пишет: "В исходном проекте языка С++ параметризованные типы учитывались, однако, их реализация была отложена из-за нехватки времени на тщательное исследование и полноценную реализацию" (как видите, великим мира сего тоже не хватает времени... но они всегда выполняли домашнее задание). В результате нескольких лет работы, к 1990 году он представил эксперементальную разработку, реализующую эту возможность, в своей книге "Annotated C++ Reference Manual". Именно эта версия определения шаблона в 1990 году была добавлена к развивающемуся стандарту ANSI C++. Теперь эта возможность поддерживается всеми основными компиляторами С++. Так что, используя Microsoft Visual C++, Вы получаете полный доступ к миру шаблонов.

Одними из главных целей, которые преследовались при разработке шаблонов, являются эффективность и простота в использовании. Неэффективные средства параметризации уже существовали к тому времени и требовалось только реализовать новый эфективный подход. Также, Страуструп считал, что использование шаблонов должно быть простым с точки зрения программиста. Вполне логично, что если языковая возможность сложна в использовании, то пользоваться ею будут немногие. Однако, благодаря мастерству Страуструпа, сегодня стало возможным осуществить все эти цели. Реализация шаблонов представляет собой огромное достижение, представляющее собой существенное дополнение к языку, как в смысле функциональности, так и в эстетическом совершенстве.

Итак, мы с Вами выяснили, что в С++ существует возможность определить обобщенный класс. Это значит, что Вы можете создать класс, который определяет все используемые в нем алгоритмы, но реальный тип обрабатываемых данных будет задан как параметр при создании объектов этого класса. Другими словами, когда Вам необходимо разработать класс, который имеет одинаковую логику работы с разными типами данных (например, класс ВЕКТОР, котрый одинаково работал бы как c данными типа int так и с double, Вашими собстенными типами данных), то лучше всего воспользоваться механизмом шаблонов.

Вот как выглядит общая форма объявления параметризованного (обобщенного) класса.

template <class Tтип_данных> class имя_класса {

//....описание класса.......

};

Рассомотрим это объявление. Здесь Tтип_данных представляет собой имя типа шаблона, которое в каждом случае конкретезации будет замещаться фактическим типом данных. При необходимости, можно определить более одного параметризовнного типа данных, используя список с разделителем-запятой, т.е. параметризованные классы могут иметь несколько аргументов шаблона. Заметим, что в пределах определения класса имя Tтип_данных можно использовать в любом месте. Когда создан параметризованный класс, Вы можете создать конкретную реализацию этого класса, используя следующий синтаксис:

имя_класса <тип_данных> объект;

В приведенном синтаксисе тип_данных представляет собою имя типа данных, над которыми фактически оперирует класс, и заменяет собой переменную Tтип_данных

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

Рассмотрим небольшой пример, посвященный шаблонам. В примере рассматривается новый для Вас синтаксис, и, поэтому, этот пример можно отнести к разряду учебных. Практический пример, как всегда, Вас ожидает в конце этого занятия.

#include <iostream.h>

//Небольшой пример на использование параметризованных классов

//собственно сам параметризованный класс

template <class T> class TestClass {

private:

T tempo;//объявим поле tempo

//какого она будет типа?

//это можно бужет выяснить ТОЛЬКО во

//время создания конкретного экземпляра класса

public:

TestClass(){tempo=0;}

T testFunc();//тестируемая функция

};

//функция-член класса TestClass

//Так как метод реализован вне класса,

//используем явное упоминание template

template <class T>

T TestClass<T>::testFunc() {

//программа выводит на экран количество байт

//занимаемое переменной tempo, типа T

cout<<"Type's size is: "<<sizeof(tempo)<<endl;

return tempo;

}

void main()

{

//создадим конкретные экземпляры класса TestClass

//char

TestClass<char> ClassChar;

ClassChar.testFunc();

//int

TestClass<int> ClassInt;

ClassInt.testFunc();

//double

TestClass<double> ClassDouble;

ClassDouble.testFunc();

}

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

В заключении, еще раз напомним, что обобщенные классы полезно использовать в тех случаях, когда класс содержит обобщенную логику. Проще говоря, используя обобщенный класс, можно создать класс, который будет управлять стеком и т.д. для любого типа данных. Компилятор автоматически сгенерирует корректный код объекта на основе типа, задаваемого при создании этого объекта.