C++ 模版类 详细讲解

模版类定义

直接先说一下模版类的定义:

template <模版类型1,模版类型2...>
class 类名
{
  内容
}

一个小示例如下:


    template<class T>
    class A 
    {
    private:
        T data;
    public:
        A(T value) :data(value) {};

        T GetData() { return this->data; }//模版函数,返回类型为T的值

    };

模版类成员函数

以上的模版函数是在类的内部定义的,如果我们要定义一个定义在类外的类模版成员函数的话,我们应该将这样的类模版成员函数定义在类的.h文件一起,定义方法如下:

template <模版类型1,模版类型2...>
返回类型 类名<模版类型1,模版类型2...>::函数名(参数1,参数2)
{
  内容
}

以下为一个示例:

template<class T>
    class A 
    {
    private:
        T data;
    public:
        A(T value) :data(value) {};

        T GetData() { return this->data; }//模版函数,返回类型为T的值

        T Test() const;
    };
    template<class T>
    T A<T>::Test() const
    {
        cout << "hello,template class" << endl;
        return data;
    }

当我们使用如下代码的时候:

A<int> intA(1);

这个时候,类模版会绑定到int类型上,然后使用int类型来实例化出特定的类,比如上面的代码就会实例化出与下面等价的类:

template<>
    class A<int> 
    {
    private:
        int data;
    public:
        A(int value) :data(value) {};

        int GetData() { return this->data; }//模版函数,返回类型为T的值

        int Test() const ;
    };
    template<>
    int A<int>::Test() const
    {
        cout << "hello,template class" << endl;
        return data;
    }

当编译器从我们的类模版A中实例化出一个类的时候,它会重写A模版,将摸板参数T的每一个实例都替换成给定的模版实参

如果一个成员函数没有被使用,它就不会被实例化。成员函数只有我们使用的时候才会实例化,当然,我们可以自己特化针对特定类型的成员函数

模版类代码区域内和代码区域外的不同模板名使用方法

在类模版自己的作用域下和在类外的模版使用方法是不同的
我写一个例子,还是如上的代码,模版类A,在类的内部写一个如下成员函数:

        A Test() 
        {
            A a1= *this;
            return a1;
        }

这个成员函数是不用写成返回值为A<T>类型的,而只需要写成A,但若是在类外定义这个函数,就必须写成刚才上面所说的格式:

    template<class T>
    A<T> A<T>::Test() 
    {
        A a1 = *this;
        return a1;
    }

我们就必须使用完整的A<T> 作为返回值
不过在函数的内部,由于我们已经进入了类的作用域,所以在定义a1的时候,无需重复模版实参。原因如下:
在类的作用域内,如果我们不提供模版实参,则编译器将默认我们的类型与成员实例化所用类型一致

因此,a1的定义实际上如下:

A<T> a1 = *this ;

模版类型别名

我们可以定义一个typedef来引用一个实例化的类:

typedef A<int> intA ;

但是我们没办法定义一个typedef引用一个模版,即无法定义一个typedef 引用A<T>
但是,新标准允许我们为类模版定义一个类型别名:

template <class> using twin_p=pair<T,T>;
twin<string> stringPair;//stringPair是一个pair<string,string>类型数据

模版类的static成员

与所有类一样,类模版也可以定义static成员:

template<class T>
    class A 
    {
    private:
        T data;
        static int static_value;
    public:
        A(T value) :data(value) {};

        T GetData() { return this->data; }//模版函数,返回类型为T的值
        static int GetValue() 
        {
            return static_value;
        }
    };

在上面的代码里面,A是一个类模版,它有一个名为static_value 的static成员变量。这代表每一个A的实例都有一个名为static_valuestatic数据成员实例
即,对任何给定类型X,都有一个A<X>::static_value ,所有A<x> 共享同一个static成员
由于每一个模版实例都有其独有的static成员,所有static的定义也要定义为模版:

template<class T> 
int A<T>::static_value = 5;    //定义并且初始化static_value

同样,我们也可以通过实例类直接访问具体的static成员:

cout << A<int>::GetValue() << endl; //  5

和其他的成员函数类似,一个static的成员函数和成员变量也只有在使用的时候才会实例化。

模版默认实参

在新标准中,我们可以为函数和模版类提供默认实参,比如如下代码(比较两个数的大小,默认使用标准库 less<T> 函数对象模版 ):

    template<calss T,calss F=less<T>>
    int compare(const T& v1, const T& v2, F f = F())
    {
        if (f(v1, v2))return -1;
        if (f(v2, v1))return 1;
        return 0;
    }

我们就将这个less<T> 绑定到F的默认参数上,当我们不使用第三个参数的时候,它就默认使用less<T> 来进行比较:

    int i = compare(1, 5);  //使用less,i=-1
    data<int> d1(1), d2(2);

    bool j = compare(d1, d2, compareData);//自己写的比较函数模版

可以看到,我们可以自己写比较函数,也可以直接用默认的比较函数,标准库里的很多东西都是如此,套路深。
最后
观察如下代码:

    template<typename T = int>
    class data
    {
    private:
        T value;
    public:
        data(T v) :value(v) {};
    };
    data<double> doublueData(3.5);
    data<>intData(4);  //空<>表示我们希望使用默认类型

我们可以给所有的模版参数都给定默认实参,且如果我们希望使用这些默认实参,我们就跟一个空尖括号对。

~结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值