类模板是用来生成类的蓝图的,与函数模板不同的是,编译器不能为类模板推导模板参数的类型,我们必须要提供额外的信息.
[1]定义类模板:
####template<typename T> class
{
}
[2]类模板的成员函数本身是一个普通的函数,但是由于类模板的每个实例都有自己的模板参数,因此定义在类模板的成员函数就必须以关键字template开头,后接模板参数.
[3]当我们在类的作用域之内使用类模板类型时可以不(当然也可以提供)提供模板实参.比如 Blob();//构造函数
[4]类模板和友元.类与友元(类或者函数)各自是否是模板是相互无关的,如果一个类模板包含一个非模板友元,则该友元对所有实例都有访问权,如果友元自身是模板,则类可以给所有友元实例授权,也可以只授权给特定实例.//注意:如果只授权给特定的实例,就必须进行前置声明.
[5]类模板的static成员,每个实例拥有各自的static成员,所以在类外定义的时候需要定义成模板.
[练习]:编写自己版本的Blob(StrBlob的模板化),并且重载必须的const成员.
#ifndef CP5_ex16
#define CP5_ex16
#include "iostream"
#include "fstream"
#include "sstream"
#include "vector"
#include "memory"
#include "initializer_list"
#include "new"
#include "string"
using namespace std;
template<typename T> class BlobPtr;
template <typename T>class Blob
{
friend class BlobPtr<T>;
public:
using size_type = typename vector<T>::size_type;
Blob() :data(std::make_shared<vector<T>>()) {};
Blob(initializer_list<T>il) : data(make_shared<vector<T>>(il)){};
Blob(const Blob & rhs){
data = make_shared<vector<T>>((*rhs.data));
}
Blob& operator= (const Blob& rhs)
{
data = make_shared<vector<T>>((*rhs.data));
return *this;
}
size_type size()const { return data->size(); };
bool empty() const { return data->empty(); }
void push_back(const T & s) { data->push_back(s); };
void pop_back() { check(0, "pop_back on empty Blob"); data->pop_back(); };
T& front(){ check(0, "front on empty Blob"); return data->front() };
T& back(){ "back on empty Blob"; return data->back(); };
const T& front()const{ check(0, "front on empty Blob"); return data->front(); };
const T& back()const{ "back on empty Blob"; return data->back(); };
const T& operator[](size_type i)const{
check(i, "subscript out of range");
return (*data)[i];
}
T& operator[](size_type i){
check(i, "subscript out of range");
return (*data)[i];
}
private:
shared_ptr<vector<T>>data;
void check(size_type, const string&)const;
};
template<typename T>
void Blob<T>::check(size_type i, const string&msg)const
{
if (i >= data->size())
throw out_of_range(msg);
}
template <typename T>
bool operator ==(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs);
template <typename T>
bool operator < (const BlobPtr<T>& lhs, const BlobPtr<T>& rhs);
template <typename T>class BlobPtr
{
friend bool operator==<T>
(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs);
friend bool operator<<T>
(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs);
public:
BlobPtr() :curr(0){};
BlobPtr(Blob<T>& a, size_t sz = 0) :wptr(a.data), curr(sz){};
bool operator != (const BlobPtr & p){ return p.curr != curr; }
T& operator*()const {
auto p = check(curr, "deference past end");
return (*p)[curr];
}
BlobPtr& operator++(){
check(curr, "the curr past the end");
++curr;
return *this;
}
BlobPtr& operator--(){
--curr;
check(curr, "the curr past the end");
return *this;
}
BlobPtr operator++(int ){
auto ret = *this;
++(*this);
return ret;
}
BlobPtr operator--(int){
auto ret = *this;
--(*this);
return ret;
}
private:
weak_ptr<vector<T>> wptr;
size_t curr;
shared_ptr<vector<T>> check(size_t, const string&)const;
};
template <typename T>
shared_ptr<vector<T>> BlobPtr<T>::check(size_t i, const string& msg)const
{
auto p = wptr.lock();
if (!p)
throw::runtime_error("unbound StrBlobPtr");
if (i >= p->size())
throw::out_of_range(msg);
return p;
}
template <typename T>
bool operator ==(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
if (lhs.wptr.lock() != rhs.wptr.lock())
throw::runtime_error("ptr to different Blob");
return lhs.curr == rhs.curr;
}
template <typename T>
bool operator < (const BlobPtr<T>& lhs, const BlobPtr<T>& rhs){
if (lhs.wptr.lock() != rhs.wptr.lock())
throw::runtime_error("ptr to different Blob");
return lhs.curr < rhs.curr;
}
#endif