C++primer 閱讀筆記-模板與泛型編程(類模板)

類模板

  • 類模板是用來生成類的藍圖
  • 與函數模板不同的是,編譯器能爲類模板推斷模板參數類型,所以在使用類模板時,需要在模板名後的尖括號裏提供額外的信息,用來補充類模板的實參
  • 類似函數模板,類模板以關鍵字template開始,後跟模板參數列表,在類模板或者其成員的定義中,用模板參數當作替身
template<typename T> class Blob{
public:
    typedef T value_type;
    typedef typename std::vector<T>::size_type size_type;
    Blob();
    size_type size() const {return data->size();}
    bool empty() {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);
private:
    std::shared_ptr<std::vector<T>> data;//使用shared_ptr和vector模板
    void check(size_type i, const std::string &msg) const;
}

實例化類模板

  • 當使用一個類模板時,必須提供額外的信息,這些信息是顯示模板實參,他們被綁定到模板參數中,編譯器利用這些模板實參來實例化特定的類
  • 編譯器從一個類模板實例化出一個類時,會用模板實參代替模板參數對應的類型或者值
  • 對指定的每種類型,編譯器生成一個不同的類
  • 一個類模板的每個實例都形成一個獨立的類

在模板作用域中引用模板類型

  • 類模板的名字不是一個類型名
  • 類模板用來實例化類型,而一個實例化的類型總是包括模板參數的
  • 一個類模板中的代碼使用另外一個模板

類模板的成員函數

  • 可以在類模板內部也可以類模板外部定義成員函數,定義在模板內的成員函數被隱式聲明爲內聯函數
  • 定義在模板外的成員函數必須以關鍵字template開始,後接類模板參數列表
  • 類模板的每個實例都有自己版本的成員函數
  • 從一個模板生成的類的名字中必須包括其模板實參
  • 當定義一個成員函數時,模板實參與模板形參相同
ret-type StrBlob::menber-name(parm-list)
//爲Blob定義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>
Blob<T>::pop_back()
{
    check(0,"pop_back on empty Blob");
    return data->pop_back();
}

類模板成員的實例化

  • 默認情況下,一個類模板的成員函數只有當程序用到他時才進行實例化,這一特性使得即使某種類型不能完全符合模板操作的要求,我們仍然能用該類型實例化類

在類代碼內簡化模板類名的使用

  • 當處於一個模板的作用域時,編譯器處理模板自身引用時,就好象我們已經提供了與模板參數匹配的實參
  • 在類模板自己的作用域中,我們可以直接使用模板名而不提供實參
template<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--();
    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;
}

在類模板作用域外

  • 在類模板作用域外必須提供模板參數
  • 知道遇到類名纔算進入類的作用域
template<typename T>
BlobPtr<T> BlobPtr<T>::operator++(int){
    BlobPtr ret = *this;
    ++*this;
    return ret;
}

類模板與友元

  • 如果類模板包括一個非模板友元,那麼該友元被授權可以訪問所有模板實例
  • 如果友元自身是模板,類可以授權給所有友元模板實例,也可以只授權給特定實例

一對一友好關係

  • 如果用類模板中的形參作爲其友元類或者函數模板的實參,那麼友好關係被限定在相同類型的實例之間
//前置聲明
template<typename> class BlobPtr;
template<typename> class Blob;
template<typename> 
    bool operator==(const Blob<T>&,cosnt Blob<T>&);

template<T> Class Blob{
    friend class BlobPtr<T> ;
    friend bool operator==<T>;
        (const Blob<T>&,cosnt Blob<T>&);
}

通用和特定的模板友好關係

  • 一個類可以將另一個模板的每個實例都聲明爲自己的友元,或者限定特定的實例爲友元:
template<typename T> Class pal;//前置聲明
class C{ //C本身是一個類,不是模板
    friend class pal<C>;//用類C實例的pal是C的一個友元
    template<typename T>friend class pal2 ;//pal2的每個實例都是C的友元    
}

*爲了讓所有實例成爲友元,友元生命中必須用與類模板本身不同的模板參數

template<Ttypename T> class C2{ //C2是模板
    friend class pal<T>;//C2的每個實例都將相同類型實例的pal視爲友元
    template<typename U>friend class pal2 ;//pal2的所有實例是C2每個實例的友元    
    friend class pal3;//pal3是非模板類,pal3是每個C2實例的友元
}

令模板自己的類型參數成爲友元

template<typename T> class Bar{
    friend T; 
}
  • T可以爲內置類型

模板類型別名

  • 定義一個typedef來引用實例化的類
typedef Blob<string> StrBlob;
  • 爲類模板定義一個類型別名
template<T> using twin = pair<T,T>;
twin<string> author;
  • 定義一個模板類型別名時,固定一個或多個參數
template<T> using twin = pair<T,unsigned>;

類模板的static成員

  • 每個類模板的實例都有自己的static成員實例,同一個類型的實例共享相同的static對象
  • 模板類的static成員有且只有一個定義
  • 類模板的每個實例都有一個獨有的static對象,我們將static數據成員也定義爲模板
    template<T> size_t Foo<T>::ctr = 0;
  • 通過類類型對像訪問一個類模板的static成員,也可以通過作用域運算符直接訪問
  • 通過類來直接訪問static成員,必須引用一個特定的實例

習題

  • 函數模板是函數的藍圖,可以把邏輯功能相同而函數參數和返回值類型不同的多個重載函數用一個函數來描述。參數化的函數稱爲函數模板,代表的是一個函數家族。
  • 類模板是類的藍圖,是對一批僅僅成員數據類型不同的類的抽像
  • 類模板被實例化時,編譯器用實參代替類中的形參來重寫類
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章