C++之模板

在C++ 中,模板为泛型程序设计奠定了关键的基础。使用模板需要用到两个关键字template 、typename ,写法:**template<typename Type>**template告诉编译器,将要定义一个模板,<>中的是模板参数列表,类似于函数的参数列表,关键字typename看作是变量的类型名,该变量接受类型作为其值,把Type看作是该变量的名称,是一个通用的类型。

函数模板

1.常规使用

建立一个通用函数模板,它所用到的数据的类型(包括返回值类型、形参类型、函数体中局部变量类型)用一个虚拟的类型(模板类型)来代替,而实际调用时编译器根据传入的实参来逆推出真正的类型,生成对应的具体的函数。这样一个通用的模板函数不仅将数据的值作为变化的量,类型也被参数化。

两个关键字:template:定义模板的关键字;typename :定义模板类型的关键字

其中T是模板参数,虚拟的类型,用于替换。在实际调用时,实参为int类型,那么会生成一个参数和返回值都为int类型的函数,由一个通用的模板函数生成具体类型的函数。编译器由函数模板自动生成模板函数的过程叫模板的实例化。

2.显示指定及默认值

如果函数的参数中并未使用模板类型,那么编译器无法自动推导,这时就需要手动的显示指定模板类型。

cpp 复制代码
#include<iostream>
using namespace std;

template<typename T>
void fun()
{
    T t = 0;
    cout << typeid(t).name() << endl; //输出变量的类型
}
int main()
{
    //在调用函数时,显式的指定
    fun<long>(); //此时模板类型T为"long"类型
    return 0;
}

除此之外还可以指定模板类型的默认类型(类似于函数参数指定默认值)

cpp 复制代码
template<typename T = long>
void fun()
{
    T t = 0;
    cout << typeid(t).name() << endl; //输出变量的类型
}
int main()
{
    fun();
    return 0;
}

模版参数类型选择的优先级:手动显示指定>编译器根据实参自动推导>模板类型默认值

示例代码:

cpp 复制代码
#include<iostream>
using namespace std;

template<typename T = long>
void fun(T t)
{
    cout << typeid(t).name() << endl; //输出变量的类型
}
int main()
{
    double a = 3.14;
    fun(a); //double

    fun<char>(a); //char
}

3.多模板参数

类似于函数参数,模板类型可以指定多个,用逗号分割,每个模板类型都需要关键字typename修饰。**template<typename T,typename K>**模板类型T替换一种类型,K则可以替换为另一种类型。多模板参数同样可以根据实参进行自动推导。不同于函数参数的默认值(从右向左依次指定,不能有间断),模板参数默认值指定的顺序可以是任意的没有强制的顺序要求 ,但在调用函数时显式指定模板类型时必须从左向右依次指定,不能有间断。

经验:编译器能够自动推导出来的模板参数放于最后,剩余的模板参数如果有默认值的放于中间,无默认值则放于前面。

例:

cpp 复制代码
template<typename T, typename K = long, typename M>
void fun(M &m);

fun<double>(10); //fun<double,long,int>
fun<double, char>(10); //fun<double,char,int>

4.模板函数的声明和定义

如果函数的声明和定义分开,那么在声明和定义处都需要加上模板,如果模板存在默认类型,那么只在函数声明时指定即可。

由于模板函数的定义并不是真正的函数,他们不能单独编译,所以不能将模板函数单独放到源文件中,模板必须与特定的模板实例化请求一起使用,所以最好的办法是模板函数的声明和定义放在一起。

类模板

与函数模板差不多,类模板也需要在类定义的上面加上templatetypename但在定义对象时,必须使用<>显式的指定模板类型。

模板类型可以替换类内的任意地方定义的类型,包括成员属性类型,成员函数。

类中成员属性若为模板类型,那么我们可以定义带参数的构造,让调用者去指定初始化值。

类模板可以有多个模板类型,且可以指定默认的模板参数,规则是从右往左依次指定不能间断(从后往前),在定义对象时从左向右指定,如果不指定模板参数,将使用默认的。

如果模板类中的成员函数在类中声明,类外实现时,函数的定义处也要加上模板,如下:

如果类模板指定了默认的类型,为了避免歧义,默认的模板类型应当去掉。

如果在模板类中声明、类外定义的成员函数存在函数模板,那么在定义的时候,两个模板都需要指定。如下:

注:这种情况下,顺序为:先类模板,后函数模板

模板类中嵌套的情况:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include<iostream>
using namespace std;

template<typename T>
class A{
public:
	T m_t;
	A(){
		m_t = 10;
	}
	A(T t) {
		m_t = t;
	}
};
class B {
public:
	A<long>m_a;
	B() {

	}
	B(long a) :m_a(a) {

	}
};

template<typename T>
class C {
public:
	A<T>m_a;
	C(T a) :m_a(a) {

	}
};

template<typename K>
class D {
public:
	K m_k;
	D(const K k) :m_k(k) {

	}
};

int main()
{
	B b;
	cout << b.m_a.m_t << endl;  //10

	B b2(30);
	cout << b2.m_a.m_t << endl; //30

	C<char>c('a');
	cout << c.m_a.m_t << endl;  //a

	A<double>aa(12.3);

	D<A<double>>d(aa);
	cout << d.m_k.m_t << endl; //12.3
}
相关推荐
xiaobai12 328 分钟前
【C/C++语言系列】实现单例模式
c语言·c++·单例模式
qmx_071 小时前
MFC -文件类控件
c++·mfc
Sunsets_Red1 小时前
Linux 系统
linux·运维·服务器·c++·学习·系统架构·系统安全
程序猿练习生2 小时前
C++速通LeetCode中等第18题-删除链表的倒数第N个结点(最简单含注释)
c++·leetcode·链表
极地星光2 小时前
设计模式-适配器模式
c++·设计模式·适配器模式
mljy.2 小时前
STL简介
c++·学习
职创未来官方2 小时前
大话C++:第11篇 类的定义与封装
c++·面向对象·封装··嵌入式物联网·访问修饰符
田小呱2 小时前
C/C++事件驱动的业务框架
c语言·c++
蠢蠢的打码2 小时前
8587 行编辑程序
数据结构·c++·算法·链表
农大蕉蕉2 小时前
C++校招面经(二)
java·开发语言·c++