КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Исключение ненужных инстанцирований функций-членов
Шаблоны Включение
Виды включения: композиция и агрегация.
В C++ ключевое слово template используется для обеспечения параметрического полиморфизма. Он позволяет применять один и тот же исходный код к разным типам, причем тип является параметром тела кода. Допустим у нас есть класс stack3, который реализует концепцию стека символов (char).
class stack3 { public: stack3(); void push(char c); char pop(); bool is_empty()const; bool is_full()const; private: enum{ max_len=100}; int top; char s[max_len];
};
Функции реализованы следующим образом:
stack3::stack3():top(0){} void stack3::push(char c){ assert(top<max_len); s[top++]=c; } char stack3::pop(){ assert(top>0); return s[--top]; } bool stack3::is_empty()const {return top==0;} bool stack3::is_full()const {return top==max_len;}
Мы можем использовать объекты этого класса следующим образом:
stack3 reverse_order(stack3 s){ stack3 tmp; while(!s.is_empty()){ tmp.push(s.pop()); } return tmp; } Пример шаблона класса: template <class T> class stack4 { public: stack4(); //конструктор void push(T c); T pop(); bool is_empty()const; bool is_full()const; private: enum{ max_len=100}; int top; T s[max_len]; };
template<class T>stack4<T>::stack4():top(0){}
template<class T>void stack4<T>::push(T c){ assert(top<max_len); s[top++]=c; }
template<class T>T stack4<T>::pop(){ assert(top>0); return s[--top]; }
template<class T>bool stack4<T>::is_empty()const {return top==0;}
template<class T>bool stack4<T>::is_full()const {return top==max_len;}
Префикс template <class T> указывает, что объявлен шаблон (template), и что в объявлении на месте T будет указан фактический тип. T – имя типа, а не обязательно класса. Имя шаблона класса, за которым следует тип, помещенный в угловые скобки <>, является именем класса (определяемого шаблона) и его можно использовать точно так же, как имена других классов: stack4<char> sc; stack4<int> si; stack4<char*> sd; Без использования шаблонов для реализации этого примера пришлось бы писать три определения классов, а с использованием шаблона – только одно определение шаблона.
Функция, работающая со стеком stack4<double>:
stack4<double> reverse_order(stack4<double> s){ stack4<double> tmp; while(!s.is_empty()){ tmp.push(s.pop()); } return tmp; }
Шаблон функции, работающий с любым стеком:
template <class STACK> STACK reverse_order(STACK s){ STACK tmp; while(!s.is_empty()){ tmp.push(s.pop()); } return tmp; }
Следует заметить, что для каждого случая инстанцирования шаблона будет генерироваться свой набор функций-членов класса, например,
stack4<char> sc;//генерируется 5 функций stack4<int> si1, si2;// генерируется 5 функций //(количество создаваемых объектов не играет роли) stack4<char> sd;//не генерируется новых функций, так как инстанцирование stack4<char> уже было выше
В нашем классе stack функции push и pop зависят от параметра шаблона, поэтому их генерирование необходимо. Так, функция push, сгенерированная для параметра char, работает не так, как функция push, сгенерированная для параметра int. В то же время функции is_empty и is_full от параметра шаблона не зависят. Функция is_empty для char абсолютно идентична функции is_empty для int. Для того, чтобы избежать генерирования лишних (полностью идентичных) функций, применяют следующий прием. Шаблонный класс создают производным от класса, не являющегося шаблоном. При этом в базовый класс помещают функции, не зависящие от параметра шаблона. Применим данный прием для нашего стека:
class stack5_base { public: stack5_base(); bool is_empty()const; bool is_full()const; protected: enum{ max_len=100}; int top; };
stack5_base::stack5_base() :top(0) {}
bool stack5_base::is_empty()const {return top==0;}
bool stack5_base::is_full()const {return top==max_len;}
template <class T> class stack5:public stack5_base { public: void push(T c); T pop(); private: T s[max_len]; };
template<class T>void stack5<T>::push(T c){ assert(top<max_len); s[top++]=c; }
template<class T>T stack5<T>::pop(){ assert(top>0); return s[--top]; }
Для нашего случая количество сгенерированных функций уменьшается до минимально необходимого:
//к этому моменту сгенерировано 3 функции для stack5_base stack5<char> sc;//генерируются 2 функции stack5<int> si1, si2;// генерируются 2 функции //(количество создаваемых объектов не играет роли) stack5<char> sd;//не генерируется новых функций, так как инстанцирование stack4<char> уже было выше
Дата добавления: 2014-01-11; Просмотров: 359; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |