C++——模板

1.函数模板
语法:

template< typename T>
函数的声明或定义

template<typename T>  //声明接下来是一个模板,T是一个通用数据类型
void func(T a, T b)  
{
}

要使用上述的函数模板,有如下两种方式:
1.自动类型推导

int a;
int b;
func(a, b);  //调用函数模板时,预先指定了a b的数据类型,进而完成自动数据类型的推导,但多个变量推导出的数据类型必须一致

2.显示指定类型,可以指定不同的数据类型

func<int>(a, b);

注:声明完函数模板后必须在接下来的函数确定下来,才能使用
2.普通函数与函数模板的区别
普通函数调用时可以发生自动类型转换,即隐式类型转换
函数模板调用时,如果利用指定类型推导,不会发生隐式类型转换
如果是显示指定类型,可以发生自动类型转换
3.普通函数与函数模板的调用规则
普通函数与函数模板发生函数重载时,优先调用普通函数
可以通过空模板参数列表的方式强制调用函数模板

func<>(a, b); //强制调用函数模板

函数模板可以发生函数重载

template<class T>
void func(T a, T b, T c)
{
}
通过如下调用重载的函数模板
func(a, b, c);

如果函数模板产生更好的匹配优先调用函数模板

void func(int a, int b, int c)
{
}
char a, b, c;
func(a, b, c) //调用时会优先调用,不用隐式类型转换去调用上面的函数

3.函数模板的局限性
某些特定的数据类型需要具体化实现
利用具体化Solution的版本实现代码,具体化会优先调用

template<>void func(Solution &S1, Solution &S2)  //通用无法完成时,优先调用此代码
{
}

4.类模板
作用:建立一个通用类,类中的成员数据类型可以不具体指定,用一个虚拟类型代表

template< class T>
紧跟一个类,与函数模板区别在于紧跟在上式后面是类而不是普通函数

template<class T1, class T2>
class Solution
{
public:
	Solution(T1 a, T2 b)
	{
		this->a = a;
		this->b = b;
	}
	T1 a;
	T2 b;
}
void test()
{
	Solution<char, int> S1('0', 5);  //用模板参数列表给T1 T2传数据类型
}

5.类模板和函数模板的区别
1.类模板没有自动类型推导使用方式
上式中test案例写成如下自动推导是错误的,必须显示指定

Solution S2('1', 5); //错误

2.类模板在模板参数列表中可以有默认参数,做如下传参

template<class T1, class T2 = int>
Solution<char> S3('2', 5); //传参数时,不会报错

6.类模板中成员函数创建时机
类模板中的成员函数在调用时,才创建;
类模板对象做函数参数:

class Per1
{
public:
	void done1{}
};
class Per2
{
public:
	void done2{}
};
template<class T>
class Solution
{
public:
	T a;   //此时会创建成功,因为没有调用done1和done2函数
	void func1()
	{
		a.done1();
	}
	void func2()
	{
		a.done1();
	}
}
下面调用类模板时,则会报错
void test()
{
	Solution<Per1> S;
	S.func1();
	S.func2();  //此时的func2无法完成调用,只确定了Per1的数据类型,完成func1的调用
}

7.类模板对象作函数参数
类模板实例化出来的对象,向函数传参的方式有三种:
1.指定传入的类型,直接显示对象的数据类型
以上式中的函数为例进行调用

void func1(Solution<char, int> &p)
{
	p.done();
}

Solution<char, int> p('0', 5);
func(p);

2.参数模板化,将对象中的参数变为模板进行传递

template<class T1, class T2>
void func2(Solution<T1, T2> &p)  //将char和int模板化
{
	p.done();
}
void test()
{
	Solution<char, int> p('0', 5);
	func2(p);
}

3.整个类模板化,将这个对象类型模板化进行传递

template<class T>
void func3(T &p)
{
	p.done();
}

8.类模板与继承
当子类继承的父类是一个类模板时,子类在声明时,要指定出父类中T的类型,如果不指定,编译器无法给子类分配内存

template<class T>
class Father
{
	T a;
}
class Son:public Father //这样无法完成继承,必须知道父类中T的数据类型,子类才能完成继承,进而分配内存空间,要指定模板的数据类型:
class Son:public Father<int>
{
	
}

如果想灵活指定出父类中T的类型,子类也必须变为类模板

template<class T1,class T2>
class Son:public Father<T2>
{
	T1 a;
}
void test
{
	Son<int, char> S; //可以灵活指定模板T的类型,父类中的T2为char,子类为int类型
}

9.类模板成员函数的类外实现
需要加上类模板的参数列表

//构造函数的类外实现
template<class T1, class T2>
//要在作用域后面标注上模板,与普通函数的类外实现相区分,表示类模板的成员函数类外实现
Solution<T1,T2>::Solution(T1 a, T2 b)
{
	this->a = a;
	this->b = b;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值