C++入门篇之模版初始篇

目录

前言

1. 泛型编程

 2. 函数模板

 2.1函数模版的格式

2.2模版的匹配原则

2.3模版的显示调用 

3. 类模板

3.1类模板的定义格式

前言

 到模版这一块了,就开始觉得C++使用起来非常方便了,可交互性很强,但是要理解其底层的实现逻辑,才能方便我们日常的调用,具有非常重要的意义,接下来我们开始模版的学习吧。

1. 泛型编程

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

我们来看函数重载的代码,如下面的Swap函数:

void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}
void Swap(double& left, double& right)
{
	double temp = left;
	left = right;
	right = temp;
}
void Swap(char& left, char& right)
{
	char temp = left;
	left = right;
	right = temp;
}

我们实现这些函数的模版都是差不多的,只是数据类型不一样,如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件 (生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只需学会使用就好了。

 2. 函数模板

 2.1函数模版的格式

template <typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}
注意点1:
typename 用来定义模板参数 关键字 也可以使用 class( 切记: 不能使用struct代替class )

举个例子:

template <class T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}
int main()
{
	int a = 1000,b = 22;
	double c = 1.1, d = 8.8;
	char e = 'A', f = 'B';
	cout << a << "   " << b << endl;
	cout << c << "   " << d << endl;
	cout << e << "   " << f << endl;
	Swap(a,b);
	Swap(c, d);
	Swap(e, f);
	cout << "交换后的数值为:" << endl;
	cout << a << "   " << b << endl;
	cout << c << "   " << d << endl;
	cout << e << "   " << f << endl;
	
	return 0;
}

运行结果如下;

 发现调用模版是不是太爽啦!根本就不需要写那么多的重载函数,那么这里我们要思考一个问题,我们没有写这些重载函数,那这些是怎么实现的呢?是编译器调用模版进行一个个的带入测试呢?还是调用模版推演出来的函数呢?

答案是肯定的,我们是调用模版推演的函数,为C++提出模板是为了节省程序员的时间,我们所省略的工作,只是编译器替我们完成了.

当我们调用 Swap(a,b);编译器会在底部推演出一个函数:

void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}

2.2模版的匹配原则

 学到这了,我们脑子里面会不会产生一个奇怪的想法呀,如果我们自己定义了一个函数,模版也可以推演出一个函数模版,那编译器会调用哪一个呢?直接编写代码,来进行测试一下:

void Swap(int& left, int& right)
{
	cout << "我是自己编写的" << endl;
	int temp = left;
	left = right;
	right = temp;
}
template <class T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}
int main()
{
	int a = 1000,b = 22;
	cout << a << "   " << b << endl;
	Swap(a,b);
	cout << "交换后的数值为:" << endl;
	cout << a << "   " << b << endl;
	return 0;
}

结果如下;

 总结如下:

匹配顺序为:

  • 如果有定义出来的函数,且类型完全匹配调用时实参类型,则执行定义出来的函数.
  • 如果定义出来的函数,不符合,则执行模板推演.

2.3模版的显示调用 

 下面来介绍一个场景,我们写的都是同类型的函数交换,如果交换的两个数不同类型呢?比如int和double,我们想到了可以类型转化:强制性转换类型,比如Swap(a,(int)b); 

这里博主引入一直显示调用的方法。

显示调用的格式为:

function<Type>(a,b,...);

 显示调用的例子:

template <class T>
T Add( const T& left,const T& right)
{
	return left + right;
}
int main()
{
	int a = 1000;
	double b = 2.2;
	Add<int>(a,b);

	return 0;
}

总结如下:

像上面的调用方式,是不允许的,因为模板中只有一个T,但是我们传了两个类型,编译器根据模板将不知道T应该是啥类型,而解决上面的问题只有两种

  • 一是强制性转换类型,比如Add(a,(int)b);
  • 二是显示使用模板,比如Add<int>(a,b);

3. 类模板

3.1类模板的定义格式

 template <class T1,class T2,...>

class class_name { };

我们用栈来写一个类的模版吧。

template <class T>
class Stack
{
public:
	Stack() :data(new T* [10]), top(0), capacity(10) 
	{}
	~Stack()
	{
		delete[] data;
		top = capacity = 0;
	}
	void Push(T& a)
	{}
private:
	T* data;
	int top;
	int capacity;
};
int main()
{
	Stack <char> st1;      //定义一个存储char类型的栈
	Stack <int> st2;       //定义一个存储int类型的栈
	Stack <double> st3;    //定义一个存储double类型的栈
	return 0;
}

注意点:

 1.类模板只是一个模板,他并不属于类.

2.对类模版的成员函数进行定义时,需要加上模版参数列表。

template<class T>
void Stack<T>::Push(T& a)
{
	//需要在void后面加上Stack<T>
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值