c++对象和类(4) - 类模板

2018-07-08 17:43:22

定义模板类的格式跟定义模板函数一样。

template <typename T>
//template <class T>
class Stack{

}

template <typename T>
Stack<T>::Stack(){

}

template <typename T>
bool Stack<T>::isempty(){

}

使用模板类

Stack<int> kernels;
Stack<string> colonels;

注意,必须显式的提供所需的类型,这与常规的函数模板是不同的,因为编译器可以根据函数的参数类型来确定要生成哪种函数。

递归使用模板

ArrayTP< ArrayTP<int,5>, 10> freecls;

使得 freecls 是一个包含10个元素的数组,其中每个元素都是一个包含5个int元素的数组。与之等价的常规数组声明如下:

int freecls[10][5];

使用多个类型参数

template <class T1, class T2>
class Pair{

}

默认类型模板参数

template <class T1, class T2 = int>
class Freecls{

}
Freecls<double> m2;  //此时T2为int

模板具体化

隐式实例化,声明对象,指出所需的类型, 编译器就会生成具体的类定义。

ArrayTP<int, 100> stuff;

显式实例化,编译器也会生成类定义。

template class ArrayTP<string, 100>;

显式具体化,相当于显式的定义一个类模板。

template <> class Classname<Type>{

}

//早期的格式
class Classname<Type>{

}

比如要提供一个 const char *类型的模板,可以使用如下代码

template <>
class Freecls<const char *>{

}

此时,有两种类模板定义

Freecls<int> scores;   //这里使用一般的模板定义

Freecls<const char *> dates;  //这里使用具体化

部分具体化

template <class T1>
class Pair<T1, int>{

}
Pair<double, double> p1;  // use general Pair template
Pair<double, int> p2;   // use Pair<T1, int> partial specialization
Pair<int, int> p3;      // use Pair<int, int> explicit specialization

template<class T>     // general version
class Feeb { ... };

template<class T*>    //指针部分具体化
class Feeb { ... }; // modified code
//如果提供非指针类型,编译器用通用版本。
//如果提供了指针,编译器用指针具体化
Feeb<char> fb1;    // use general Feeb template, T is char
Feeb<char *> fb2;   // use Feeb T* specialization, T is char

如果没有进行部分具体化,则第二个声明将使用通用模板,将T转换为 char * 类型。如果进行了部分具体化,则第二个声明将使用具体化模板,将T转换为 char。

// general template
template <class T1, class T2, class T3> class Trio{...};
// 具体化 T3 设置为 T2
template <class T1, class T2> class Trio<T1, T2, T2> {...};
// 具体化 T3 和T2 设置为 T1*
template <class T1> class Trio<T1, T1*, T1*> {...};
Trio<int, short, char *> t1;    // use general template
Trio<int, short> t2;            // use Trio<T1, T2, T2>
Trio<char, char *, char *> t3;   //use Trio<T1, T1*, T1*>

将模板用作参数

// stacktp.h -- a stack template
#ifndef STACKTP_H_
#define STACKTP_H_
template <class Type>
class Stack
{
    private:
        enum {MAX = 10};    // constant specific to class
        Type items[MAX];    // holds stack items
        int top;            // index of top stack item
    public:
        Stack();
        bool isempty();
        bool isfull();
        bool push(const Type & item);   // add item to stack
        bool pop(Type & item);          // pop top into item
};

template <class Type>
Stack<Type>::Stack()
{
    top = 0;
}

template <class Type>
bool Stack<Type>::isempty()
{
    return top == 0;
}

template <class Type>
bool Stack<Type>::isfull()
{
    return top == MAX;
}

template <class Type>
bool Stack<Type>::push(const Type & item)
{
    if (top < MAX)
    {
        items[top++] = item;
        return true;
    }
    else
        return false;
}

template <class Type>
bool Stack<Type>::pop(Type & item)
{
    if (top > 0)
    {
        item = items[--top];
        return true;
    }
    else
        return false;
}

#endif
// tempparm.cpp -- templates as parameters
#include <iostream>
#include "stacktp.h"

template <template <typename T> class Thing>
class Crab
{
    private:
        Thing<int> s1;
        Thing<double> s2;
    public:
        Crab() {};
        // assumes the thing class has push() and pop() members
        bool push(int a, double x) { return s1.push(a) && s2.push(x); }
        bool pop(int & a, double & x){ return s1.pop(a) && s2.pop(x); }
};

int main()
{
    using std::cout;
    using std::cin;
    using std::endl;
    Crab<Stack> nebula;
// Stack must match template <typename T> class thing
    int ni;
    double nb;
    cout << "Enter int double pairs, such as 4 3.5 (0 0 to end):\n";
    while (cin >> ni >> nb && ni > 0 && nb > 0)
    {
        if (!nebula.push(ni, nb))
            break;
    }

    while (nebula.pop(ni, nb))
        cout << ni << ", " << nb << endl;
    cout << "Done.\n";

    return 0;
}

template <typename T> class 是类型,Thing是参数。

可以混合使用模板参数和常规参数

template <template <typename T> class Thing, typename U, typename V>
class Crab{
private:
    Thing<U> s1;
    Thing<V> s2;
    ...
Crab<Stack, int, double> nebula; // T=Stack, U=int, V=double


非模板友元

template <class T>
class HasFriend
{
friend void report(HasFriend<T> &); // bound template friend
...
};

//声明
HasFriend<int> hf;

//替换后
class HasFriend<int>
{
    friend void report(HasFriend<int> &); // bound template friend
    ...
};

模板类的约束模板友元函数

//在类定义前面声明每个模板函数
template <typename T> void counts();
template <typename T> void report(T &);

//然后在函数中将模板声明为友元
template <typename TT>
class HasFriendT
{
    ...
    friend void counts<TT>();
    friend void report<>(HasFriendT<TT> &);
};

上面的 report() 的<>可以为空,因为可以从函数参数推断,然而也可以这样

friend void report<HasFriendT<TT> >(HasFriendT<TT> &);
HasFriendT<int> squack;

//替换后
class HasFriendT<int>
{
    ...
    friend void counts<int>();
    friend void report<>(HasFriendT<int> &);
};

模板类的非约束模板友元函数

通过在类内部声明模板,可以创建非约束友元函数。

template <typename T>
class ManyFriend
{
    ...
    template <typename C, typename D> friend void show2(C &, D &);
};
#include <iostream>
using std::cout;
using std::endl;

template <typename T>
class ManyFriend
{
    private:
        T item;
    public:
        ManyFriend(const T & i) : item(i) {}
        template <typename C, typename D> friend void show2(C &, D &);
};

template <typename C, typename D> void show2(C & c, D & d)
{
    cout << c.item << ", " << d.item << endl;
}

int main()
{
    ManyFriend<int> hfi1(10);
    ManyFriend<int> hfi2(20);
    ManyFriend<double> hfdb(10.5);
    cout << "hfi1, hfi2: ";
    show2(hfi1, hfi2);
    cout << "hfdb, hfi2: ";
    show2(hfdb, hfi2);

    return 0;
}

c++11模板别名

模板别名也可以用 typedef 来模拟。

typedef std::array<double, 12> arrd;
typedef std::array<int, 12> arri;
typedef std::array<std::string, 12> arrst;
arrd gallons;   // gallons is type std::array<double, 12>
arri days;     // days is type std::array<int, 12>
arrst months;  // months is type std::array<std::string, 12>


template<typename T>
using arrtype = std::array<T,12>;

arrtype<double> gallons;      // std::array<double, 12>
arrtype<int> days;            // std::array<int, 12>
arrtype<std::string> months;  // std::array<std::string, 12>

c++11还有等价于 typedef 的用法。

typedef const char * pc1;    // typedef syntax
using pc2 = const char *;      // using = syntax
typedef const int *(*pa1)[10]; // typedef syntax
using pa2 = const int *(*)[10]; // using = syntax


//这里的typename用来标记std::vector<T>::iterator是类型而非变量
typename std::vector<T>::iterator e = elems.begin();
//这里就可以保证下面语句是声明一个指针而非乘法
typename std::vector<T>::iterator *e


©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。