C++模板初阶

C++泛型编程

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

如何实现一个通用的交换函数:

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++中支持的函数重载新特性来实现的,但是缺点在于:

  1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
  2. 代码的可维护性比较低,一个出错可能所有的重载均出错

在C++中,存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件

(即生成具体类型的代码) 因此我们又可以引申出泛型编程的基础:模板

泛型编程的基础:模板

C++模板初阶_第1张图片

函数模板

函数模板概念 :

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定
类型版本。

函数模板格式 :

template

后接函数体定义。(typename是用来定义模板参数关键字,也可以使用class)

#include

using namespace std;
// 函数模板和同名函数可以同时存在
// 
// 1.有现成,用现成的
// 2.有现成,但是不够匹配,有模板,选择实例化模板
// 3.有匹配也有模板,但是显式实例化模板(强制使用模板)
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;
}

// 函数模板使用:告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码
// typename是用来定义模板参数关键字,也可以使用class

//template
template
void Swap(T& s1, T& s2)
{
	T tmp;
	tmp = s1;
	s1 = s2;
	s2 = tmp;
}
// 隐式实例化:让编译器根据实参推演模板参数的实际类型
// 显式实例化:在函数名后的<>中指定模板参数的实际类型

int main()
{
	int a, b;
	a = 1;
	b = 0;
	char str1, str2;
	str1 = 'a';
	str2 = 'b';

	cout << "交换前:" << endl;
	cout << "a=" << a << " b=" << b << endl;
	cout << "str1=" << str1 << " str2=" << str2 << endl;

	swap(a, b);
	swap(str1, str2);

	cout << "交换后:" << endl;
	cout << "a=" << a << " b=" << b << endl;
	cout << "str1=" << str1 << " str2=" << str2 << endl;
	return 0;
}

注意:函数模板和同名函数可以同时存在:调用时候遵循以下规则:

  1. 有现成且匹配的函数,用现成的函数
  2. 有现成的函数,但是不够匹配,有模板,选择实例化模板
  3. 有匹配的函数也有模板,但是显式实例化模板(强制使用模板)

函数模板是一个蓝图,它本身并不是函数,是编译器根据使用方式产生特定具体类型函数的模具。所以模板就是将本来应该我们做的重复的事情(写重复相似的代码)交给了编译器来做

函数模板的实例化:

隐式实例化:让编译器根据实参推演模板参数的实际类型

template
T Add(const T& left, const T& right)
{
    return left + right;
}
int main()
{
    int a1 = 10, a2 = 20;
    double d1 = 10.0, d2 = 20.0;
    // ok!
    Add(a1, a2);
    Add(d1, d2);
    
    // ok?
    //Add(a1, d1);
    /*
    该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
    通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,
    编译器无法确定此处到底该将T确定为int 或者 double类型而报错
    注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅
    */
    
    // 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化
	Add(a, (int)d);//强转 
    Add(a, b);//显式实例化
    return 0;
}

显式实例化:在函数名后的<>中指定模板参数的实际类型

int main(void)
{
    int a = 10;
    double b = 20.0;
    // 显式实例化
    Add(a, b);
    return 0;
}

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

你可能感兴趣的:(C++学习专栏,c++,开发语言)