您的位置:首页 > 编程语言 > C语言/C++

C++ 模板与泛型(2)

2016-01-26 15:37 519 查看

C++ 模板与泛型之类模板

一个类模板的每个实例都形成一个独立的类,与函数模板不同是,编译器无法推断实参类型,必须由程序员显示的提供模板实参作为额外信息。

类模板的成员函数只在程序用到它的时候才进行实例化,这也就意味着,某种类型如果不能完全符合模板定义的所有操作,我们仍然能够使用该类型对模板进行实例化。

示例

C++ Primer


Blob
BlobPtr
两个模板为例对类模板进行说明,现整理完整代码
(注:之前提到过C++模板不支持分离式编译,所以声明和定义都在同一个.h文件中。)


[code]//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


[code]//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及智能指针进行实例化的过程。

总结

类模板与函数模板类似,类模板的名字不是一个类型名,而是用来实例化类型的,一个实例化的类型需要程序员显示的提供模板实参,类模板的每个实例都形成一个独立的类。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: