C++模板使用

 感谢你的阅读!!!


目录

 感谢你的阅读!!!

举个例子:

template

有什么意义为什么要用模板

与typedef的区别

使用方法

模板:隐式实例化与显示实例化

和非模板函数以及多个模板类函数重载情况

类模板声明与定义


有什么意义为什么要用模板

int add(int a,int b)
{
    return a+b;
}

float add(float a,float b)
{
    return a+b;
}

char add(char a,char b)
{
    return a+b;
}

 观察述代码,代码功能相同,只是类型不同。

为了更快,更方便的使用代码完成任务,避免一直写一些数据类不同而任务相同的函数。

模板的诞生将程序员从任务相同数据类型不同的函数中解放出来。

什么是函数模板?

C++提供了模板(template)编程的概念。所谓模板,实际上是建立一个通用函数或类,其类内部的类型和函数的形参类型不具体指定,用一个虚拟的类型来代表。这种通用的方式称为模板。模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。

举个例子:

在古代模板就一块板子,在一本书的复制,如果靠手写不止到猴年马月才可以推广,但是在伙子印刷术的出现,大大的加快了书籍的推广。。。。

代码例子:template <typename NAME>

 使用方法 关键字template <typename Name>

template <typename Ty>
Ty add(const Ty&a,const Ty&b)
{
    return a+b;
}


int main()
{
    cout<<add(1,2)<<endl;
    return 0;
}

模板原理

在主函数中打印表达式中的add函数会根据传入的形参类型确定模板类型,然后再参数出自动推导类型。

模板实例化

那有个问题来了,模板是函数吗?

其实很好回答的,跨海大桥图纸是跨海大桥吗?不是的

让我们看下面这段代码

 我们将i1,i2、d1,d2 、ch1,ch2,分别传入swap函数进行交换,运行代码

发现确实交换了,那么可以说我们的模板其实是一个函数咯?其实模板只是模板而这里是使用了根据模板造的3个Swap函数

 根据传入的参数类型编译器推演类型,确定生成哪一类临时函数进行完成任务。这也是模板函数的实例化,生成了三个临时函数对象。

所以这里的函数其实是3个不同类型形参的Swap()。

模板匹配参数匹配原则

1:存在普通函数与模板函数重载

2:多个模板函数

1、普通函数与模板函数

模板函数与普通函数构成函数重载。

 运行程序,发现我们的调用的是,确定类型的add函数,而不是模板add函数。

原因:编译器推导模板有效率上的消耗,所以我们在调用函数时会先找是否有类型匹配的函数,无匹配后才会使用模板函数。

如果是实参类型没有确定类型匹配的函数,则会调用模板函数。

2、多个模板函数

情况一:不允许 

 这是不被允许的,编译时就会报错。

情况二:允许

 

 这里函数调用也会有情况发生。

一、形参相同调用模板一

实参a和f都是浮点类型。

二、形参相同调用模板二

实参a为整型类型、f为浮点类型。

与typedef的区别

如果是typedef为类型其别名的话,它其实也是为了便利函数,但是在上述的代码中它是十分不利的

 一个函数只能完成一个类型数据的交换,如果需要同时交换数据那只能写多个Swap函数进行函数重载了,但是加上自定义类型的话,那么要写的Swap重载函数需要太多太多的,但是使用模板进行书写,就只关心传入的数据了

模板使用方法

template关键字+<class/typename name>注意这里的class不能使用struct代替!!!!!

存在函数模板与类模板。

模板的调用分:隐式实例化与显示实例化

隐式实例化:

template <typename Ty>
Ty Add(const Ty& a, const Ty& b)
{
	return a + b;
}
int main()
{
	cout << Add(1, 2) << endl;
	return 0;
}

没有指定Add函数参数类型,编译器自动识别实参类型进行推演后实例化Swap函数,进行完成任务。

Ty Add(const Ty& a, const Ty& b)
{
	return a + b;
}
//...1和2传入,推演类型为int,模板实例化
int Add(const int& a, const int& b)
{
	return a + b;
}

显示实例化

有一种情况,如果Add的两个实参类型不一样

Ty Add(const Ty& a, const Ty& b)
{
	return a + b;
}
int main()
{
	cout << Add(1, 2.2) << endl;//int,double
	return 0;
}

这个时候编译器将不知道应该为哪一种函数类型

 解决方法一:传入数据强制类型转换

Add(1,(int)1.1);
//或者
Add((double)1,1.1);

虽然可以完成任务,但是加大了程序员的负担,不推荐

解决方法二:设置两个模板。

template <typename Ty,typename Tx>
Ty Add(const Ty& a, const Tx& b)
{
	return a + b;
}
int main()
{
	cout << Add(1, 2.2) << endl;

这样虽然解决了传入不同参数的方法,但是在返回值的时候是根据a的数据类型为返回值类型的,加大了我们程序员的复杂性。一般推荐

解决方法三:使用显示模板实例化

显示的实例化,不在根据实参类型实例化我们的函数,根据我们自己的要求实例化函数

template <typename Ty,typename Tx>
Ty Add(const Ty& a, const Tx& b)
{
	return a + b;
}
int main()
{
	cout << Add<int,int>(1, 2.2) << endl;

无论Add类型如何,我们的实例化的函数形参类型都是int,int类型。

这样我们可以更加随心所欲的使用模板实例化函数了。

和非模板函数以及多个模板类函数重载情况

与非模板函数:

当模板函数与我们的非模板函数同名是,会根据类型函数调用函数。

运行代码:

发现调用

为什么会发生这样的事情呢?因为推演有时间的

调用Add函数的时候会先看代码中是否有参数类型匹配的函数定义,如果有就会调用匹配函数,如果没有才会根据模板实例化相应函数,然后调用实例化函数。

与模板函数

因为推演会有时间上的损耗,所以两个模板不同名字相同的函数会有区别

也是根据实参类型,使用不同的模板,这里我们不深究,这样的情况我们在日常工作中很少遇见,找到就好了。

类模板必须显示实例化

为什么类模板必须显示实例化?

为了类中出现任何成员函数中可以使用模板,必须显示实例化模板:必须提供模板参数,以便编译器可以生成实际的类(或函数,来自函数模板)。

        如st1我们隐式实例化,我们就无法知道我们的TData的替换是说明类型数据了,这样在类成员函数中以及成员变量我们就不知道该类型是什么类型了,所以我们的必须显示实例化类实例化对象,如st2,我们就实例化了保存char类型一个类=>栈。否则,我们将不知道该栈存储的是什么数据了。

        所以,如果说类是对象的图纸,那么类模板就是类的图纸。对类也要实例化产生实例的类。


这里有一个注意的地方!!!

模板为什么不支持声明定义分离在两个文件?如何解决?

为什么?

模板函数确定对象函数是在编译阶段确定的。

在编译器编译阶段,对应模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。如果定义在两个文件中,模板函数将找不到模板定义,导致编译报错。

类模板声明与定义不要分离(声明在.h,定义在.cpp )

也就是说,一个类模板实现,函数的声明与定义不能分别在不同的文件中。

解决方法

        1、声明和定义不分离一起写。

       2、同一个文件内可以实现类模板成员函数声明定义分离。但是我们在类域外定义的时候也要进行模板的操作

 感谢你的阅读!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云的小站

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值