类模板使用和深入

我们在编写不同类型的参数的类时,特别是对于容器类,除了想保存的对象类型不同外,代码都相同,这时候我们希望一种泛型的类,我们可以将具体的类型用参数的形式传递给它,而不用每次都去实现。

c++的类模板为生成通用的类声明提供了一种很好的方法。这也是代码重用的重要的一部分。

首先怎样定义一个模板类:

template <class Type>

关键字template 是告诉编译器,将定义一个模板。尖括号内容相当于是参数列表,关键字class 看做是变量的类型名,Type是变量的名称。

当然了使用class并不意味着只能用类做参数,这只是表明Type是一个通用的类型说明符,在模板的实例化是将使用具体的类型替代它,我们也可以使用typename 来代替class

template <typename Type>

<span style="font-size:18px;">template <class Type>
class Stack{
private:
     Type items[10];
     int top;
public:
     Stack();
     bool push(const Type & item);
...
};

template <class Type>    //每个函数头都将以模板声明开始
Stack<Type>::Stack(){    //类限定符也要加上模板类型
     top = 0;
}
template <class Type>
 bool Stack<Type>::push(const Type & item){
...
}</span>

重要的一个概念就是:

模板不是类,也不是成员函数。它们只是c++编译器指令,说明了如何生成类和成员函数。模板的具体实现是由实例化和具体化 来完成的。

我们一般将模板信息放入头文件中,在使用的时候包含头文件。

接下来就是如何使用模板类,我们需要声明一个类型为模板类的对象,方法使用具体的类型作为参数。

比如,Stack<int > st;   Stack<double> st2;

使用Int 来替换Type   ,double 来替换Type。

注意我们赋给类型参数的只能是类型,不能是数字。必须显示的提供所需的类型。


模板类扩展:

1,模板中非类型参数的使用

template <class T,int n>

关键字class指出T为类型参数,int 指出n的类型为Int ,这种参数称为非类型参数(表达式参数)。

表达式参数有一些限制:表达式参数可以是整型,枚举,引用,指针。模板代码不可以修改参数的值,也不能使用参数的地址。比如n++ ,&n等。


2,模板的多功能性

递归使用模板:对于数组模板Array,可以Array< Array<int ,5> , 10> twodee;

这样我们就得到一个包含10个元素的数组,每个元素都是包含5个Int 元素的数组。

模板可以包含多个类型参数:template <class T1,class T2>;

默认类型参数模板:template <class T1,class T2 = int> class topo;

如果我们实例化的时候省略T2,编译器将使用int。


模板的具体化:

具体化可以分为隐式实例化,显示实例化,显示具体化,部分具体化。

1,隐式实例化

指出所需类型,声明一个或多个对象,主要用途是创建对象。

pt = new Array<double,20>;

编译器生成类定义,然后根据定义创建一个对象。 

2,显示实例化

使用关键字template 并指出所需类型来声明类。

template class Array<string,20>;

没有创建对象,只是生成类声明。

3,显示具体化

它是针对特定类型的定义。具有具体定义的模板,不同于泛型定义模板

template <> class Array(const char *) {...};

这是一个专供char * 类型使用的模板。

在实例化时遵循一个原则:当具体化模板和通用模板与实例化匹配时,编译器优先使用具体化模板。

4,部分具体化

给类型参数的其中之一指定具体类型

template <class T1> class Pair<T1,int > {...};

关键字template 后面的<>声明里是没有被具体化的类型参数,如果为空,表示显示具体化、

template <> class Pair<int ,int> {...};

如果有多个模板可供选择,编译器将使用具体化程度最高的模板。


模板的使用场景:

1,模板做为成员

template <class T>
class Bete{
private:
    template <class V>
    class hold{
    private:
        V val;
    public:
        hold(V v = 0):val(v){ }
        void show() const {cout << val << endl;}
    };
    hold <T> q;
    hold <int > n;
public:
    beta(T t,int i):q(t),n(i){}
...
};

这是beta模板中声明和定义hold方法,q成员是基于类型T的hold对象。

如果在beta模板中声明hold方法,在外面定义它,就会出现模板嵌套。

tempate <class T>
class Bete{
private:
    template <class V>
    class hold;
    hold<T> q;
    hold <int> n;
...
};
template <class T>
    template <class V>
        class Bete<T>::hold{ 
        private:
            V val;
        public:
         ...
        };

2,模板作为参数

模板可以包含本身就是模板的参数。

template <template <typename T> class Thing>

class Crab{

Thing <int > s1;

Thing <int > s2;

...

};

template <typename T>

class King{

...

};

模板参数是emplate <typename T> class Thing
我们将用KIng<int > 替换Thing<int>


模板和友元:

模板的友元分为三类:非模板友元,约束模板友元,非约束模板友元

1,非模板友元

将模板类中一个常规函数声明为友元,称为模板所有实例化的友元。

为友元函数提供模板类参数,如果要使用,需要显示具体化。

template <class T>

class HasFriend{

pulbic:

    friend void reports(HasFriend<T> &);

...

};

void reports(HasFriend <int > & hf){ }

void reprots(HasFriend <double> & hf) {}

report()并不是模板函数,只是使用一个模板类参数,定义的时候,需要传递给它具体的类型。上面定义的两个report()函数,分别是两个特定HasFriend具体化的友元。

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

友元函数成为模板,友元类型取决于类被实例化的类型。

template <class T> void couts();

template <class T> void reports(T &); // 第一步,声明模板函数

template <class TT>

class HasFriend{

    friend void couts<TT> ();               //第二步,将模板声明为友元

    friend void reports<> (HasFriend<TT> &);

};

template <class T>                      //第三步,提供模板定义

void couts{

cout << ... << endl;

}

couts()函数没有参数,因此要使用<>来指明具体化类型,reports()函数有参数,可以从参数推断出模板类型参数,所以<>可以为空。

在使用的时候,couts<int >(),couts<double> (),

HasFriend<int> hf1;

HasFrined<double> hf2;

reports(hf1);  //根据函数参数类型

reports(hf2);


3,非约束模板友元函数

在类内部声明模板,每个函数具体化都是每个类具体化的友元。

tempalet <class T>

class Many{

    template <class C,class D>friend void show(C & ,D &);

};

template <class C,class D> void show(C & c,D & d){

cout << .. << endl;

}

show()函数是所有具体化的友元。


所有这些机制,都是为了让我们能够重用经过测试的代码。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值