C++ 类模板

一、定义类模板

类模板和函数模板类似,只是提供如何生成类和成员函数的模板,并不是定义类和成员函数

1、类模板声明格式

template <typename 类型参数> //typename可用class替换 
class 类名
{
    类成员声明 
};

2、类模板定义对象的格式

类模板名<真实类型参数表> 对象名(构造函数实际参数表);

如果类模板有无参构造函数,那么也可以使用如下写法:

类模板名<真实类型参数表> 对象名;

示例:

#include <iostream>
using namespace std;

//类模板
template <typename T>
class Add
{
private:
    T m_a;
    T m_b;

public:
    Add(T a, T b)
    {
        m_a = a;
        m_b = b;
    }

    T Sum()
    {
        return (m_a + m_b);
    }
};

int main()
{
    Add<int> a(1, 2); //模板类
    int sum = a.Sum();
    cout << "sum = " << sum << endl;

    return 0;
}

运行结果:

sum = 3

3、类模板定义模板成员函数的格式

1)、在类模板声明中定义

与普通类的成员函数的定义方法一致。这种情况下属于内联定义

template <typename T>
class Add
{
private:
    T m_a;
    T m_b;

public:
    Add(T a, T b)
    {
        m_a = a;
        m_b = b;
    }

    T Sum() //类中定义
    {
        return (m_a + m_b);
    }
};

2)、在类模板外定义

需要加模板前缀和类限定符,不需要类名

template <typename T>
class Add
{
private:
    T m_a;
    T m_b;

public:
    Add(T a, T b)
    {
        m_a = a;
        m_b = b;
    }

    T Sum();
};

template <typename T> //类外定义需要加模板前缀和类限定符
T Add<T>::Sum()
{
    return (m_a + m_b);
}

4、类模板、模板类与对象的关系

在这里插入图片描述

二、类模板的派生

可以从类模板派生出新的类,既可以派生类模板,也可以派生非模板类

1、从类模板派生出新的类模板

格式:

template <class T>
class Base
{
	//TODO
};

template <class T>
class Derive : public Base<T>
{
	//TODO
};

与一般的类派生定义相似,只是在指出它的基类时要缀上模板参数,即Base< T >

2、从类模板派生非模板类

可以从类模板派生出非模板类,在派生中,作为非模板类的基类,必须是类模板实例化后的模板类,并且在定义派生类前不需要模板声明语句:template< class T>。

template <class T>
class Base
{
	//TODO
};
class Derive : public Base<int>
{
	//TODO
};

在定义Derive类时,Base已实例化成了int型的模板类。

三、类模板的多功能性

1、递归使用模板

template <typename T, int n> //声明Array类模板
class Array
{
private:
    //TODO

public:
    //TODO
};

Array< Array<int, 5>, 10> arr;

这里arr是包含10个元素的数组,其中每个元素都是一个包含5个int元素的数组。类似于int [10][5];

2、模板可以包含多个类型参数

template <typename T1, typename T2> 
class Array
{
private:
    //TODO

public:
    //TODO
};

3、模板可以有默认类型参数

template <typename T1, typename T2 = int> 
class Test
{
private:
    //TODO

public:
    //TODO
};

Test<double> t2; 		 //T1是double类型,T2是int类型
Test<double, double> t1; //T1和T2都是double类型的,覆盖默认参数

4、成员模板

模板可用作结构、类或模板类的成员

5、模板可用作参数

模板可以包含类型参数(typename T)和非类型参数(如int),还可以包含本身就是模板的参数

四、模板具体化

模板的隐式实例化、显式实例化和显式具体化统称为具体化

1、隐式实例化

template <typename T, int n> //声明Array类模板
class Array
{
private:
    //TODO

public:
    //TODO
};

Array<double, 10> a; //隐式实例化

编译器在需要对象之前,不会生成类的隐式实例化

Array<double, 10> *P; 		//不需要对象,不会实例化
p = new Array<double, 10>;  //需要对象,此时实例化

示例:

#include <iostream>
using namespace std;

template <typename T>
class A
{
private:
    T m_a;

public:
    A(T a)
    {
        m_a = a;
    }

    void print()
    {
        cout << "m_a = " << m_a << endl;
    }
};

int main()
{
    A<int> a(10); //隐式实例化
    a.print();
}

运行结果:

m_a = 10

2、显式实例化

显式实例化和隐式实例化一样,也是根据通用模板来生成具体化。
显式实例化的声明必须位于模板定义所在的名称空间中。
显式实例化虽然没有创建对象,但是编译器会生成类声明,包括方法定义

格式:

template class 类模板名<实际类型列表>;
#include <iostream>
using namespace std;

template <typename T>
class A
{
private:
    T m_a;

public:
    A(T a)
    {
        m_a = a;
    }

    void print()
    {
        cout << "m_a = " << m_a << endl;
    }
};

//显式实例化
template class A<int>;

int main()
{
    A<int> i(4);
    i.print();
}

结果:

m_a = 4

3、显式具体化

显式具体化是用于替换模板中泛型的特定类型,是对模板进行修改的特殊实例化

格式:

template class <> className(specialized-type-name) {...};

示例:

#include <iostream>
using namespace std;

template <typename T>
class A
{
private:
    T m_a;

public:
    A(T a)
    {
        m_a = a;
    }

    void print()
    {
        cout << "m_a = " << m_a << endl;
    }
};

//显式具体化
template <>
class A<int>
{
private:
    int m_a;

public:
    A(int a)
    {
        m_a = a;
    }

    void print()
    {
        cout << "m_a*m_a = " << m_a * m_a << endl;
    }
};

int main()
{
    A<float> f(10.1); //隐式实例化
    f.print();

    A<int> i(4); //使用具体化模板
    i.print();
}

运行结果:

m_a = 10.1
m_a*m_a = 16

4、部分具体化

1)、格式

template <class T1, class T2>  //类模板
class className
{
	//TODO
}

template <class T1>  //部分具体化
class className<T1, int>
{
	//TODO
}

2)、注意事项

1、当类模板参数只有一个参数时,部分具体化其实就是显示具体化
2、可以将所有的参数都具体化,此时template后面的<>为空。template <> class A<int, int> {…}
3、当给定多个模板时,编译器选择使用具体化程度最高的那个。例如:

template <class T1, class T2> class A {...}; //模板1
template <class T1> class A<T1, int> {...};  //模板2
template <> class A<int, int> {...}; 		 //模板3

A<double, double> p1; //使用模板1
A<double, int> p1;    //使用模板2
A<int, int> p1;       //使用模板3

示例

#include <iostream>
using namespace std;

template <typename T1, typename T2>
class A
{
private:
    T1 m_a;
    T2 m_b;

public:
    A(T1 a, T2 b)
    {
        m_a = a;
        m_b = b;
    }

    void print()
    {
        cout << "m_a*m_b = " << m_a * m_b << endl;
    }
};

template <class T1>
class A<T1, int>
{
private:
    T1 m_a;
    int m_b;

public:
    A(T1 a, int b)
    {
        m_a = a;
        m_b = b;
    }

    void print()
    {
        cout << "m_a*m_b = " << m_a * m_b << endl;
    }
};

int main()
{
    A<float, int> obj(1.2, 4);
    obj.print();
}

结果

m_a*m_b = 4.8

5、显式实例化和显式具体化的区别

显式实例化只是显式声明模板需要示例化为哪种类型,同隐式实例化一样依然是根据类模板进行实例化;显式具体化不是根据类模板进行实例化的,是类模板的修改版本

五、类模板的注意事项

类模板的声明和定义必须在同一个文件中,即不能将声明放在头文件中,而实现放在源文件中

参考:
1、《C++ Primer Plus》
2、类模板

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值