C++ 模板与泛型之类模板
一个类模板的每个实例都形成一个独立的类,与函数模板不同是,编译器无法推断实参类型,必须由程序员显示的提供模板实参作为额外信息。
类模板的成员函数只在程序用到它的时候才进行实例化,这也就意味着,某种类型如果不能完全符合模板定义的所有操作,我们仍然能够使用该类型对模板进行实例化。
示例
在C++ Primer中
以Blob 和 BlobPtr两个模板为例对类模板进行说明,现整理完整代码(注:之前提到过C++模板不支持分离式编译,所以声明和定义都在同一个.h文件中。)
//Blob.h
//该模板类通过shared_ptr对vector进行管理,并通过友元的BlobPtr伴随类对自己进行监控。
#ifndef BLOB_H_
#define BLOB_H_
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include "BlobPtr.h"
template <typename> class BlobPtr;
template <typename> class Blob;
template <typename T>
bool operator==(const Blob<T>&, const Blob<T>&);
template <typename T> class Blob{
public:
typedef T value_type;
typedef typename std::vector<T>::size_type size_type;
//construct
Blob();
Blob(std::initializer_list<T> il);
//元素数目
size_type size() const{ return data->size(); }
bool empty()const { return data->empty(); }
//添加与删除
void push_back(const T & t){ data->push_back(t); }
//移动版本
void push_back(T &&t){ data->push_back(std::move(t)); }
void pop_back();
//元素访问
T& back();
T& operator[](size_type i);
friend class BlobPtr < T > ;//友元声明
friend bool operator==<T>(const Blob<T>&, const Blob<T>&);//友元声明
private:
std::shared_ptr<std::vector<T>> data;
//若data[i]无效,则抛出msg
void check(size_type i, const std::string &msg)const;
};
//构造函数
template <typename T>
Blob<T>::Blob() :data(std::make_shared<std::vector<T>>()){}
//构造函数
template <typename T>
Blob<T>::Blob(std::initializer_list<T> il) : data(std::make_shared<std::vector < T >> (il)){}
//check是否越界
template <typename T>
void Blob<T>::check(size_type i, const std::string &msg)const
{
if (i >= data->size())
{
throw std::out_of_range(msg);
}
}
//元素访问
template <typename T>
T& Blob<T>::back()
{
check(0, "back on empty Blob");
return data->back();
}
//[]运算符重载元素访问
template <typename T>
T& Blob<T>::operator[](size_type i)
{
check(i, "subscript out of range");
return (*data)[i];
}
//弹出
template <typename T>
void Blob<T>::pop_back()
{
check(0, "pop_back on empty Blob");
data->pop_back();
}
#endif
//BlobPtr.h
//该模板类维护指向Blob的弱引用,用来进行元素访问和监控Blob对象
#ifndef BLOBPTR_H_
#define BLOBPTR_H_
#include <iostream>
#include<vector>
#include <memory>
#include "Blob.h"
template <typename> class Blob;
template <typename T>
class BlobPtr{
public:
BlobPtr() : curr(0){};
BlobPtr(Blob<T> &a, size_t sz = 0) :wptr(a.data), curr(sz){}
T &operator *() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
BlobPtr &operator++();//前置运算符
BlobPtr &operator--();
BlobPtr<T> operator++(int);
BlobPtr<T> operator--(int);
private:
std::shared_ptr<std::vector<T>>check(std::size_t, const std::string&)const;
std::weak_ptr<std::vector<T>>wptr;
std::size_t curr;//当前索引
};
//check函数
template <typename T>
std::shared_ptr<std::vector<T>>
BlobPtr<T>::check(std::size_t i, const std::string& msg) const
{
auto ret = wptr.lock(); //判断wptr是否绑定了Blob
if (!ret)
throw std::runtime_error("unbound BlobPtr");
if (i >= ret->size())
throw std::out_of_range(msg);
return ret;
}
//前置递增
template <typename T>
BlobPtr<T>& BlobPtr<T>::operator++ () {
check(curr, "increment past end of BlobPtr"); //先判断后加
++curr;
return *this;
}
//前置递减
template <typename T>
BlobPtr<T>& BlobPtr<T>::operator-- () {
--curr; //先减之后, 如果为0, 再减就是大整数
check(curr, "decrement past begin of BlobPtr"); //先减后判断
return *this;
}
//后置递增
template <typename T>
BlobPtr<T> BlobPtr<T>::operator++(int)
{
BlobPtr ret = *this;
++*this;
return ret;
}
//后置递减
template <typename T>
BlobPtr<T> BlobPtr<T>::operator--(int)
{
BlobPtr ret = *this;
--*this;
return ret;
}
#endif
编写main,进行单步调试就很容易看到其实质是使用类模板参数对成员函数、成员vector及智能指针进行实例化的过程。
总结
类模板与函数模板类似,类模板的名字不是一个类型名,而是用来实例化类型的,一个实例化的类型需要程序员显示的提供模板实参,类模板的每个实例都形成一个独立的类。
3万+

被折叠的 条评论
为什么被折叠?



