【c++】模板

目录

模板

1. 泛型编程

泛型编程概念:

2. 函数模板

概念

格式

原理

实例化

隐式实例化

显式实例化

模板参数的匹配原则

3.类模板

定义格式

举例

实例化

模板实现动态顺序表


模板

    这篇博客我们要说的是:泛型编程,函数模板,类模板

1. 泛型编程

  我们先来看一段代码

void Swap_int(int &a, int &b)
{
	int temp = a;
	a = b;
	b = temp;
}
void Swap_char(char &c, char &d)
{
	char cur = c;
	c = d;
	d = cur;
}

  我们可以看到上面两个交换函数, 除了参数的类型之外其它的逻辑是完全一样的,那么我们要是在一个程序中交换一种类

型就写一个对应类型的Swap函数,岂不是太繁琐了,那么我们能不能实现出一个通用的函数,当我们需要传哪个类型就传哪

个类型呢?

    当然可以,函数重载就可以实现,但是函数重载代码的复用率太低,一旦有新的类型出现,就需要增加对应的函数,并

且代码的可维护性太低,一个出错可能会导致所有重载全部出错

    所以我们有了更加好的方法, 就是模板,那么什么是模板呢,就相当于一个模型, 你往里面倒什么样的材料就给你出什

么材料的东西,并不需要每个材料都弄一个模具,这样太浪费了

    所以我们就引入了一个概念叫做泛型编程,而模板就是泛型编程的基础


泛型编程概念:

    编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础

 

2. 函数模板

概念

  函数模板代表了一类函数,该函数模板与类型无关,使用的时候才被参数化,根据传入的实参类型来确定特定类型的版本

格式

template<typename T1, typename T2.......typename Tn>

template <class T>
void Swap(T &a, T &b)
{
	T temp = a;
	a = b;
	b = temp;
}

注意: typename是用来定义模板参数关键字,也可以使用class, 但是不能用struct代替class

原理

  在编译阶段, 对于函数模板, 编译器会根据传入的实参类型来推演生成对应的函数来供用户使用,当我们用int类型使用函数

模板时,编译器将T确定为int类型,然后产生一份专门处理int类型的代码,那么对于char和double也是一样的.

实例化

隐式实例化

    让编译器根据实参推演模板参数的实际类型

template <class T>
T Add(const T &a, const T &b)
{
	return a + b;
}
int main()
{
	int a = 10;
	int b = 2;
	Add(a, b);
	return 0;
}

  我们转到反汇编来看: 

    可以看到编译器通过参数类型推演生成了一个int类型对应的函数 , 因为我们传的是两个int类型的参数, 编译器可以自动识

别, 然后实例化出一个参数为int类型的函数, 这种实例化就叫做隐式实例化.

显式实例化

    在函数名后的<>中指定模板参数的实际类型

   当我们传入一个int和一个double的时候, 这个时候就出错了, 显示没有与函数模板Swap匹配的类型, 是因为我们传入了一个int和一个double, 编译器不知道到底按int类型生成还是按照double类型生成, 这个有两种方法 : 1.强转 2.显示实例化

1. 强转

template <class T>
T Add(const T &a, const T &b)
{
	return a + b;
}
int main()
{
	int a = 10;
	double b = 0.2;
	Add(a, (int)b);
	return 0;
}

2. 显式实例化

template <class T>
T Add(const T &a, const T &b)
{
	return a + b;
}
int main()
{
	int a = 10;
	double b = 0.2;
	Add<int>(a, b);
	return 0;

如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错

模板参数的匹配原则

1. 非模板函数和同名的模板函数同时存在

template <class T>
T Add(const T &a, const T &b)
{
	cout << "模板函数" << endl;
	return a + b;
}
int Add(int &a, int &b)
{
	cout << "非模板函数" << endl;
	return a + b;
}
int main()
{
	int a = 10;
	int b = 2;
	Add(a, b);
	return 0;
}

运行结果:

 我们可以看到当我们现在已经有了匹配的非模板函数时, 会调用非模板函数, 现成的已经有了, 就会调用已经有了的这个.

2.  如果非模板函数的参数和实参的类型不一样, 只能去实例化

template <class T>
T Add(const T &a, const T &b)
{
	cout << "模板函数" << endl;
	return a + b;
}
int Add(int &a, int &b)
{
	cout << "非模板函数" << endl;
	return a + b;
}
int main()
{
	double a = 10;
	double b = 2;
	Add(a, b);
	return 0;
}

3. 非模板函数的参数没有模板函数的更匹配, 会走模板函数

template <class T,class T1>
bool fun(const T &a, const T1 &b)
{
	cout << "模板函数" << endl;
	return a > b;
}
bool fun(const int &a, const int &b)
{
	cout << "非模板函数" << endl;
	return a > b;
}
int main()
{
	//a为int, b为double
	int a = 10;
	double b = 2;
	fun(a, b);
	return 0;
}

运行结果:

虽然非模板函数也可以运行, 但是毕竟是相当于double转换为int, 精度不够, 编译器这个时候就会实例化一个更匹配函数.

4.如果存在非模板函数, 且类型匹配, 但是指定显示实例化, 则必须实例化

template <class T,class T1>
bool fun(const T &a, const T1 &b)
{
	cout << "模板函数" << endl;
	return a > b;
}
bool fun(const int &a, const int &b)
{
	cout << "非模板函数" << endl;
	return a > b;
}
int main()
{
	//a为int, b为double
	int a = 10;
	int b = 2;
	fun<int>(a, b);
	return 0;
}

运行结果:

 

3.类模板

定义格式

template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};

举例

     我们定义一个结构体, 现在我们可以看到, 编译器已经报错了, _data只能存放int类型的数据, 可是我们想存char怎么办, 那就是模板

template <class T>
struct Vector
{
	T _data;
};
int main()
{
	Vector<int> v1;
	v1._data = 1;
	Vector<char> v2;
	v2._data = 'a';
	cout << v1._data << endl;
	cout << v2._data << endl;
	return 0;
}

 我们可以定义自己想要存放的类型

运行结果:

实例化

  类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模

板名字不是真正的类,而实例化的结果才是真正的类。

  比如上面的Vector<int>, 才是类型, Vector只是一个类名

模板实现动态顺序表

template <class T>
class Vector
{
public:
	Vector(int capacity = 10)
		:_data(new T[capacity])
	{}
	
	void push_back(const T& val)
	{
		//应该检查容量, 在这里就只实现简单逻辑了,主要是看看模板的使用
		_data[_size++] = val;
	}
	void dispay()
	{
		for (size_t  i = 0; i < _size; i++)
		{
			cout << _data[i] << ' ';
		}
		cout << endl;
	}
private:
	T* _data;
	size_t _size;
	size_t _capacity;
};

int main()
{
	Vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	v.dispay();
	Vector<char> v1;
	v1.push_back('a');
	v1.push_back('b');
	v1.push_back('c');
	v1.push_back('d');
	v1.push_back('e');
	v1.dispay();
	return 0;	
}

运行结果:

 以上就是关于模板一些简单的知识和应用

 

 

    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值