[C++系列]终于有一篇完整的函数模板,类模板,特化及模板分离编译归纳总结了

在这里插入图片描述

前言

众所周知使用函数重载虽然可以实现一个较为通用的函数,但其仅仅只是类型不同,代码的可复用率是比较低的,只要有新的类型出现,就需要增加对应的函数,代码的可维护性也是比较低的,一个出错可能所有的重载都会出现错误,因此我们也是引入了模板的概念来帮助我们解决这样的问题。

1.泛型编程

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

template < typename / class 泛型参数1typename / class泛型参数2.....>
{
	函数定义
}

泛型编程并没有减少实际的代码量,只是把重复的代码交给机器自动生产,减少开发人员重复的工作量,极大的提高工作效率。

2. 函数模板及特化

2.1函数模板

函数模板本身并不是函数,是将本来应该我们做的事情交给编译器去做。
在这里插入图片描述

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

template <class T>
T add(T a, T b)
{
	return a + b;
}

template <class T1,class T2>
T2 Add(const T1& a, const T2& b)
{
	return a + b;
}

int Add(const int& a, const int& b)
{
	return a + b;
}

  • 普通函数与模板函数共存时,如果普通函数的参数类型可以完全匹配,则执行普通函数,不进行函数模板的实例化,顾名思义就是吃现有的饭,不去考虑还没有做好的饭。
  • 如果普通函数和模板函数共存,普通函数参数类型不完全匹配,而实例化函数可以完全匹配,则进行模板的实例化。
  • 若普通函数和模板函数共存,指定了需要实例化Add<int>(a,b),则进行实例化。

2.2 函数模板的特化

函数模板
template <class T>
T Add(T& a, T& b)
{
	return a + b;
}

函数模板的特化
template <>
char* Add<char*>(char*& a, char*& b)
{
	strcat(a, b);
	return a;
}

普通函数
char* Add(char*& a, char*& b)
{
	strcat(a, b);
	return a;
}
  • 对于函数模板不能够处理的特殊类型,一般会定义一个此类型的普通函数,函数模板你的特殊会比较少用
template <class T, size_t N>
class Array
{
private:
	T _array[N];
};
  • 模板参数可分为:类型模板参数(class, typename), 非类型模板参数(数值类型)
  • 非类型模板参数: 可以作为常量使用, 它的值需要在编译时确定

3. 类模板及特化

3.1 类模板

template <class T1, class T2, class T3>
class Date
{
public:
	Date(T1 year, T2 month, T3 day)
		:_year(year)
		, _month(month)
		, _day(day)
	{}

	void Display();
	/*{
		cout << _year << "-" << _month << "-" << _day << endl;
	}*/
private:
	T1 _year;
	T2 _month;
	T3 _day;
};
template <class T1, class T2, class T3>
void Date<T1, T2, T3>::Display()
{
	cout << _year << "-" << _month << "-" << _day << endl;
}
  • 如果在类外定义类模板的成员函数,需要加上泛型的声明,作用域为“类名<泛型参数>”
  • 类模板不能进行隐式实例化,需要在类模板名字后跟 <>

3.2 类模板的特化

特化之前需要存在基础类模板
template <class T1, class T2>
class A
{
public:
	A()
	{
		cout << "A(T1, T2)" << endl;
	}
private:
	T1 _t1;
	T2 _t2;
};

全特化--> 所有的参数都为具体类型
template <>
class A<int, char>
{
public:
	A()
	{
		cout << "A(int, char)" << endl;
	}
private:
	int _t1;
	char _t2;
};



偏特化: a. 部分特化
template <class T1>
class A<T1, double>
{
public:
	A()
	{
		cout << "A(T1, double)" << endl;
	}
private:
	T1 _t1;
	double _t2;
};

template <class T1>
class A<T1, char>
{
public:
	A()
	{
		cout << "A(T1, char)" << endl;
	}
private:
	T1 _t1;
	double _t2;
};

b. 对模板参数做进一步的限制
template <class T1, class T2>
class A<T1&, T2&>
{
public:
	A()
	{
		cout << "A(T1&, T2&>" << endl;
	}
};

4. 模板分离编译

一个程序由若干个源文件共同实现,每个源文件单独编译生成目标文件,最后将所有的目标文件链接起来形成单一可执行文件的过程称之为分离编译模式。

a.h
template<class T>
bool IsEqual(const T& a, const T& b);

a.cpp
template<class T>
bool IsEqual(const T& a, const T& b)
{
	return a==b;
}

main.cpp
#include"a.h"
int main()
{
	IsEqual(1, 1);
	IsEqual(1.0, 2.0);
	return 0;

在这里插入图片描述
因此如果需要对上方所出现的问题进行解决的话,有两种方法:

  1. 将声明和定义放到一个文件“xxx.h”里面,推荐使用这种
  2. 模板定义的时候使用显式实例化,但是不实用。

5. 模板总结

在这里插入图片描述
【优点】

  1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
  2. 增强了代码的灵活性
    【缺陷】
  3. 模板会导致代码膨胀问题,也会导致编译时间变长
  4. 出现模板编译错误时,错误信息非常凌乱,不易定位错误

猜你喜欢

转载自blog.csdn.net/Luckily0818/article/details/106892625