【CC++】基础:模板

【C/C++】基础:模板

  1. 代码将会放到: https://gitee.com/liu-hongtao-1/c–c–review.git ,欢迎查看;
  2. 欢迎各位点赞、评论、收藏与关注,大家的支持是我更新的动力,我会继续不断地分享更多的知识;
  3. 文章多为学习笔记,以综述学习的重点为主,可能有一些细节没有提及或把握不到位,感谢理解;

一、泛型编程

现有问题:C++提供的函数重载,可以处理参数类型不同功能相同的函数。但是,无法实现自动识别函数类型的功能,从而降低了代码的复用性。而且代码的可维护性比较低,一个出错可能所有的重载均出错。故而引入泛化编程。

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

C++处理:使用模板template

二、函数模板

2.1 概述

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

使用:

template<typename T1, typename T2,......,typename Tn>
template<class T1, class T2,......,class Tn>
返回值类型 函数名(参数列表){}

实现原理:在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用然后产生一份专门处理相关类型的代码

示例:

template<typename T1,typename T2>
template<class T1,class T2>
void PrintTypeName(T1 x,T2 y) {
	cout << "T1: " << typeid(x).name() << endl;
	cout << "T2: " << typeid(y).name() << endl;
}
int main() {
	int x = 1;
	double y = 2;
	PrintTypeName(x, y);
}
T1: int
T2: double

注意:

  • 模板需要实例化为不同函数,因此调用的不是同一个函数

    从汇编的角度去看:call的是不同的函数地址

    	PrintTypeName(x, y);
    0064245C  sub         esp,8  
    0064245F  movsd       xmm0,mmword ptr [y]  
    00642464  movsd       mmword ptr [esp],xmm0  
    00642469  mov         eax,dword ptr [x]  
    0064246C  push        eax  
    0064246D  call        PrintTypeName (06413E3h)  
    00642472  add         esp,0Ch  
    	PrintTypeName(y, x);
    00642475  mov         eax,dword ptr [x]  
    00642478  push        eax  
    00642479  sub         esp,8  
    0064247C  movsd       xmm0,mmword ptr [y]  
    00642481  movsd       mmword ptr [esp],xmm0  
    00642486  call        PrintTypeName (0641460h)  
    0064248B  add         esp,0Ch  
    
  • typename可以使用class替代,但不能用struct

  • 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换,否则会产生歧义

2.2 实例化

  • 显示实例化:在函数名后的<>中指定模板参数的实际类型,如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

  • 隐示实例化:让编译器根据实参推演模板参数的实际类型。当产生歧义时,编译器一般不会进行类型转换操作,此时有两种处理方式:1. 强制转化 2. 使用显式实例化

    template<class T1,class T2>
    void PrintTypeName(T1 x,T2 y) {
    	cout << "T1: " << typeid(x).name() << endl;
    	cout << "T2: " << typeid(y).name() << endl;
    }
    int main() {
    	int x = 1;
    	double y = 2;
    	PrintTypeName(x, y);//隐示实例化
    	PrintTypeName<int,float>(x, y);//显示实例化
    }
    

2.3 匹配原则

  • 一个非模板函数和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。若与非模板函数匹配,编译器不需要实例化,否则需要编译器实例化函数模板

  • 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板函数。

  • 实验如下:

    template<class T1,class T2>
    void PrintTypeName(T1 x,T2 y) {
    	cout << "T1: " << typeid(x).name() << endl;
    	cout << "T2: " << typeid(y).name() << endl;
    }
    
    void PrintTypeName(int x, int y) {
    	cout << "no template" << endl;
    	cout << "T1: " << typeid(x).name() << endl;
    	cout << "T2: " << typeid(y).name() << endl;
    }
    int main() {
    	cout << "experiment 1:" << endl;
    	PrintTypeName(1, 1);
    	cout << "experiment 2:" << endl;
    	PrintTypeName(1, 1.0);
    }
    
    experiment 1:
    no template
    T1: int
    T2: int
    experiment 2:
    T1: int
    T2: double
    

三、类模板

使用:

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

实例化:类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>
中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

示例:

template<class T1, class T2>
class A {
private:
	T1 _a;
	T2 _b;
public:
	A(T1 a,T2 b)
		:_a(a),
		_b(b)
	{}
	void Print() {
		cout << "a:" << _a << " b:" << _b << endl;
	}
};

int main() {
	A<int, double> a(1, 1.2);
	a.Print();
}

你可能感兴趣的:(c语言,c++,开发语言)