模板以及泛型编程

(1)模板机制:将类型变成需要指定的参数,从而实现共用代码;

(2)类模板:定义一个类,变量类型以及方法的返回类型参数类型都需要用参数指定,主要用于容器;

和抽象类区分开来,类模板是一个具体的类类型;

(3)模板的定义template <typename T>,且方法的定义都需要放到头文件中,因为在创建模板实例之前就需要知道完整的定义。

(4)一个典型的模板定义如下:

//定义前面加一行表示这是一个模板,需要给类型参数T制定值
template <typename T>
class Grid
{
public:
    Grid(size_t inWidth=kDefaultWidth,size_t inHeight=kDefaultHeight);
    virtual ~Grid();
    void setElementAt(size_t x,size_t y,const T& inElem);
    T& getElementAt(size_t x,size_t y);
    const T& getElementAt(size_t x,size_t y)const;

    size_t getHeight() const{return mHeight;}
    size_t getWidth() const{return mWidth;}
    static const size_t kDefaultWidth=10;
    static const size_t kDefaultHeight=10;

private:
    void initializeCellsContainer();
    std::vector<std::vector<T>> mCells;
    size_t mWidth,mHeight;
};

//模板的每个方法定义前面都要加模板说明
template <typename T>
Grid<T>::Grid(size_t inWidth,size_t inHeight):mWidth(inWidth),mHeight(inHeight)//Grid后面要加<T>
{
    initializeCellsContainer();
}

template <typename T>
Grid<T>::~Grid()
{

}

template <typename T>
void Grid<T>::initializeCellsContainer()
{
    mCells.resize(mWidth);
    for(std::vector<T>& colum:mCells)
    {
        colum.resize(mHeight);
    }
}

template <typename T>
void Grid<T>::setElementAt(size_t x,size_t y,const T& inElem)
{
    mCells[x][y]=inElem;
}

template <typename T>
T& Grid<T>::getElementAt(size_t x,size_t y)
{
    return mCells[x][y];
}

template <typename T>
const T& Grid<T>::getElementAt(size_t x,size_t y) const
{
    return mCells[x][y];
}
和正常的类定义类似,只是定义方法的时候需要注意格式的问题

(5)模板的实例化

Grid<int> myIntGrid;//指定数据类型,采用默认参数进行初始化
Grid<double> myDoubleGrid(11,11);//采用给定参数进行初始化
myIntGrid.setElementAt(0,0,10);
int x=myIntGrid.getElementAt(0,0);

Grid<int> grid2(myIntGrid);//复制构造函数
Grid<int> anotherIntGrid;
anotherIntGrid=grid2;//赋值
不仅可以保存数据类型,还可以保存其它类或者是指针等类型:

    //使用SpreadsheetCell作为模板类型
    Grid<SpreadsheetCell> mySpreadsheet;
    SpreadsheetCell myCell("test");
    mySpreadsheet.setElementAt(3,4,myCell);

    //使用指针类型作为模板类型
    Grid<const char*> myStringGrid;
    myStringGrid.setElementAt(2,2,"hello");

    //使用另一模板作为类型
    Grid<vector<int>> gridOfVectors;
    vector<int> myVector{1,2,3};
    gridOfVectors.setElementAt(5,6,myVector);
编译器无法编译模板定义,因为不知道模板的数据类型,实例化其实就是将模板定义中的每一个T换成用户实例化的数据类型(int,char*...);

(6)可以给模板指定非类型参数如下:

template <typename T,size_t  WIDTH,size_t  HEIGHT>,编译之前就知道参数的值

这样在写模板方法的时候,需要加上这些参数如下:

template <typename T ,size_t  WIDTH,size_t HEIGHT>
Grid<T,WIDTH,HEIGHT>::Grid(){...}

在实例化的时候需要:Grid<int,10,10> myGrid;

限制:不能使用非常量整数初始化实例;

  Grid<int,10,10>和Grid<int,10,11>是两种不同的类型,不能互相赋值,或者当成参数;

(7)可以对某个方法定义模板;

(8)可以从类模板中派生一个新的类模板;

(9)函数模板:为不知道输入类型的函数定义模板

template <typename T>
size_t Find(T& value,T* arr,size_t size)
{
    for(size_t i=0;i<size;i++)
    {
        if(arr[i]==value)
            return i;
    }
    return (size_t)(-1);
}
调用方式:

res = Find<int>(x,intArr,sizeIntArr);

(10)模板别名的使用,typedef和using的区别:

使用typedef时候,必须给出T的类型:typedef MyTemplateClass<int> otherName;

typedef MyTemplateClass<T> otherName;是错误的

但是可以用:using otherName=MyTemplateClass<T>;

(11)替换函数语法

关键字decltype:将表达式作为实参,返回该表达式的类型;

在模板中,有时候并不知道函数返回值的类型,那么函数的定义可以如下:

template<typename Type1,typename Type2>

auto func(const Type1& t1,const Type2& t2)->decltype(t1+t2){return t1+t2;}

decltype(t1+t2)不能放在前面,因为那个时候t1和t2还没有定义

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值