C++ class templates(2)---《C++ Templates》
来源:互联网 发布:一键转发微信源码编程 编辑:程序博客网 时间:2024/06/03 16:33
摘要:
1)讲具体类型当做template arguements传入才能使用class template。于是该class template便以你所指定的那些类型,由编译器实例化并编译;
2)class template之中,只有被实际调用的成员函数,才能被实例化;
3)针对某些特定类型,可以针对class template进行全特化和偏特化;
4)可以为template parameters定义默认值,即预设模板变量值。
**
实作class template stack
**
#include <vector>#include <stdexcept>template <typename T>class Stacck{private: std::vector<T> elems;public: void push(T const&); void pop(); T top() const; bool empty() const{ return elems.empty(); }};template <typename T>void Stack<T>::push(T const& elem){ elems.push_back(elem);}template <typename T>void Stack<T>::pop(){ if(elems.empty(){ throw std::out_of_range("Stack<>::pop: empty stack"); } T elem=elems.back(); elems.pop_back(); return elem;}template <typename T>T Stack<T>::top() const{ if(elems.empty()){ throw std::out_of_range("Stak<>::top empty stack"); } return elems.back();}
这个class template是以标准库的class template vector<>为基础构建起来的。这里的typename也可以用class进行代替,这两个几乎没有差异,我么也可以为自己声明Stack类声明copy构造函数和assignment运算符,可以这样写:
template <typename T>class Stack{ ... Stack(Stack<T> const&); Stack<T>& operator=(Stack<T> const&); ...};
然而如果只是需要class名称而不是class类型时,只需写Stack即可,构造函数和析构函数的声明属于这种情况。
**
使用class template
**
#include <iostream>#include <string>#include <cstdlib>#include "stack.hpp"int main(){ try{ Stack<int> intStack; Stack<string> stringStack; intStack.push(7); std::cout<<intStack.pop()<<std::endl; stringStack.push("hello"); std::cout<<stringStack.top()<<std::endl; stringStack.pop(); stringStack.pop(); }catch(std::exception const& ex){ std::cerr<<"Exception:"<<ex.what()<<std::endl; return EXIT_FAILURE; }}
需要注意的是,惟有被调用到的成员函数,才会被实例化。对于class template而言,只有当某个成员函数被调用时候,才回进行实例化。无疑这样做可以节省时间和空间。另一个好处是,你甚至可以实例化一个class template,而具体实现类型并不需要完整支持内部的部分不会被调用到的函数,举例如下:考虑么讴歌class,其某些成员函数使用operator<对内部元素进行排序;只要避免调用这些函数,就可以以一个不支持operator<的类型来实例化这个class template。
运用typedef,你可以更方便地使用class templates:
typedef Stack<int> IntStack;void foo(IntStack const& s){ IntStack isStack[10]; ...}Stack<float*> floatPtrStack;Stack<Stack<int> > intStackStack;//Stack of Stack
注意,你必须在相邻的两个右角括号之间插入一些空白符号,否则就等于使用了operator>>,就会导致语法错误。
**
class Template的特化
**
针对某些特殊的template arguments,对一个class template进行特化,class template特化与fucntion template的重载类似,使你得以针对某些特定类型进行程序代码优化,或者修正某个特定类型在class template实例中的错误行为。如果你对一个class template进行特化,就必须特化所有成员函数。
特化必须以template<>开头声明此一class,后面耕者你希望的特化结果,特化类型将作为template arguments并在class名称之后直接写明:
template <>class Stack<std::string>{ ...};//特化函数而言,每个T出现处都应该更换为特化类型void Stack<std::string>::push(std::string const& elem){ elems.push_back(elem);}
下面给出一个针对std::string类型特化Stack<>的完整示例:
#include <deque>#include <string>#include <stdexcept>#include "stack.hpp"template<>class Stack<std::string>{private: std::deque<std::string> elems;public: void push(std::string const&); void pop(); std::string top() const; bool empty() const{ return elems.empty(); }};void Stack<std::string>::push(std::string const& elem){ elem.push_back(elem);}void Stack<std::string>::pop(){ if(elems.empty()){ throw std::out_of_range("Stack<std::string>::pop():empty stack"); } elems.pop_back();}std::string Stack<std::string>::top() const{ if(elems.empty()){ throw std::out_of_range("Stack<std::string>::top(): empty stack"); } return elems.back();}
该例中,我们在stack类中改用deque来管理替代元素,这样做并没有特别的好处,但它示范了一个特化实作码可以和其primary template有一定程度的差异,哈哈,这是不是类似于function template中函数重载呀!
**
偏特化(Partial Specialization)
**
class template不仅可以被全特化,更重要的是其可以被偏特化,强大吧!这时的我们可以在特定情况下使用特殊实作码,但仍然留给使用者选择template parameter的能力!例如针对如下class template:
template <typename T1,typename T2>class MyClass{ ...}
以下书中形式的偏特化都是合理的:
template <typename T>class MyClass<T,T>{ ...};
template <typename T>class MyClass<T,int>{ ...};
template <typename T1,typename T2>class MyClass<T1*,T2*>{ ...};
MyClass<int,float> mif;//使用Myclass<T1,T2>Myclass<float,float> mff;//使用Myclass<T,T>MyClass<float,int> mfi;//使用MyClass<T,int>MyClass<int*,float*> mp;//使用<T1*,T2*>MyClass<int,int> m;//使用???,匹配了两种MyClass<int*,int*> m;//使用???,匹配了两种
为了解决上面的歧义性,可以针对相同类型的指针,再提供一种偏特化版本:
template <typename T>class MyClass<T*,T*>{ ...};
**
预设模板自变量
**
我们可以针对class template定义其template parameters的默认值,称为default template arguments(预设模板自变量)
#include <vector>#include <stdexcept>template <typename T,typename CONT=std::vector<T> >class Stack{private: CONT elems;public: void push(T const&); void pop(); T top() const; bool empty() const{ return elems.empty(); }}//因为template现在有两个参数,因此每一个成员函数的定义式中都必须包含这两个参数template <typename T,typename CONT>void Stack<T,CONT>::pop(){ if(elems.empty()){ throw std::out_of_range("Stack<>::pop(): empty stack"); } elems.pop_back();}template <typename T,typename CONT>T stack<T,CONT>::top() const{ if(elems.empty()){ throw std::out_of_range("Stack<>::top(): empty stack"); } return elems.back();}template <typename T,typename CONT>void Stack<T,CONT>::push(T const& elem){ elems.push_back(elem);}
调用
#include <iostream>#include <deque>#include <cstdlib>#include "stack.hpp"int main(){ try{ Stack<int> intStack; Stack<double,std::deque<double> >dblStack; intStack.push(7); std::cout<<intStack.top()<<std::endl; intStack.pop(); dblStack.push(42.42); std::cout<<dblStack.top()<<std::endl; dblStack.pop(); dblStack.pop(); }catch(std::exception const& ex){ std::cerr<<"Exception:"<<ex.what()<<std::endl; return EXIT_FAILURE; }}
注意上述代码中的intStack和dblStack的声明方式。
- C++ class templates(2)---《C++ Templates》
- C++templates简单基础--Function Templates
- c++Templates学习笔记(一)
- c++Templates学习笔记(二)
- c++Templates学习笔记(三)
- Templates
- templates
- Templates
- Templates
- Templates
- templates
- templates
- templates
- C++ use Templates(function && class)
- Class templates类模板
- 《C++Templates》第二章-初探函数模板
- [已解决]sourcetree warning: templates not found C:\Program Files (x86)\Git\share\git-core\templates
- C++ function templates(1)---《C++ Templates》
- PHP从命令行接收参数
- MFC透明动画实例
- nyoj 17单调递增最长子序列
- shell脚本
- python 一些函数介绍
- C++ class templates(2)---《C++ Templates》
- Vacations
- JavaScript使用正则表达式
- DNS服务器搭建
- linux系统编程模拟火车售票
- spark常见问题汇总
- 从包图分析逻辑层架构
- 有符号数与无符号数之间的运算
- 第7章 IoC容器 VI (Component) -- Spring4.3.8参考文档中文版