C++【泛型编程】

谭书:谭浩强版《C++程序设计(第3版)》
Cpp:《C++ Primer Plus(第6版)》
EC:《Effective C++(第3版)》

一、模板

函数模板【CppP231】

声明:
template<typename Type> 
void fun(Type a,float b);
定义:
template<typename Type>
void fun(Type a,float b){……}

(1)函数模板本身不会创建任何函数,只有在调用函数模板时才会根据实际情况创建相应的实际函数
(2)最终的程序不会包含函数模板,只包含创建的实际函数
(3)函数模板的重载与普通函数的重载相同,需要函数特征标不同,与函数类型无关:
	 void fun(Type a,float b);
	 void fun(Type a,char b);
(4)函数模板可能无法处理某些数据类型
	 比如给fun(Type a,float b)传递实参fun(s,1.0),其中s是结构体变量,fun中的某些语句可能无法应用到结构体变量s上
	 这时候需要对特定类型的数据单独编写具体化的模板定义,即“显式具体化”

函数模板的具体化【CppP234】

函数模板的具体化:都是使用具体类型的函数定义,而不是通用描述

(1)显式实例化:直接命令编译器以int创建对应的实际函数。借用模板来生成函数定义,并不专门写函数定义。
	 声明时实例化:template void fun<int>(int,float);  //此时template后面不写<typename Type>
	 使用时实例化:fun<int>(1.0,2.0);  //发现第一个参数不是int型,则将1.0强制转换为int型
	 
(2)隐式实例化:借用模板来生成函数定义,并不专门写函数定义
	 使用时实例化:fun(1,2.0);  //编译器发现第一个参数类型为int,则以int创建对应的实际函数
	 
(3)显式具体化:有自己专门的函数定义
	 声明时具体化:template <> void fun<int>(int,float);
	              template <> void fun(int,float);  //<int>可以省略,两种声明等价,因为函数的参数列表中,第一个参数的类型由模板的Type具体为int
	 函数定义:    template <> void fun<int>(int,float){……}
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————
总结:
(1)调用的优先顺序: 非模板函数 > 显式具体化 > 常规函数模板
	 void fun(int,float);
	 template <> void fun<int>(int,float);
	 template<typename Type> void fun(Type,float);
(2)不要在同一个文件中使用同一种类型的显式实例化和显示具体化:
	 template void fun<int>(int,float);
	 template <> void fun<int>(int,float);
	 调用时会出现歧义

类模板【谭书P293 CppP463 P470】

类模板声明:
template <class Type,int n> //n为非类型参数,可以是:整型、枚举、引用、各种指针
class A{……}

(类内)定义类模板的成员函数:
Type max(Type x1,Type x2){……}

(类外)定义类模板的成员函数:
template <class Type,int n>
Type A<Type,n>::max(Type x1,Type x2){……} //第一个Type指的是max函数的返回值类型为Type

类模板定义对象:
A <int,3> a1(1,2);
————————————————————————————————————————————————————————————————————————————————————————————
(1)类模板不是真正的类,类模板的成员函数体也不是函数的定义。类模板是编译器指令,说明了如何生成类和成员函数定义。
(2)在调用时,即实例化时才生成一个对应的类及其成员函数,如A <int,3> a1(1,2)和A <float,5> a1(1,2)分别生成了两个相互独立的类
(3)应该把类模板的类体、成员函数体(整个类模板的东西)放在同一个头文件中,使用时包涵这个头文件
(4)类模板可以作为基类,派生出派生类模板
(5)在类模板内可以写缩写A,在类外必须使用完整的:A<Type,n>
(6)默认类型模板参数:
	 template <class Type1=int,int n=5> 
	 class A{……}
	 使用时:A<> a; // 模板参数均有默认值,使用时,类模板<>不能省略,函数模板<>可以省略
(7)类型参数默认值:类模板可用,函数模板不可用(C++11开始函数模板也可用类型参数默认值)
	 非类型参数默认值:类模板、函数模板均可用

类模板的具体化【CppP473】

类模板的具体化:模板以泛型的方式描述类,具体化使用具体的类型生成类声明

(1)显式实例化:使用关键字template并指出所需类型来声明类。该声明必须位于模板定义所在的名称空间中。
	 template class A<int,3>; //此时虽然没有创建对象,但也将生成具体的类声明
	 
(2)隐式实例化:在创建对象时,给出所需的类型,编译器使用模板的描述来生成具体的类
	 A <int,3> a1(1,2);
	 在创建对象之前,编译器不会生成具体的类声明:
	 A<int,3> *p; 	   //不生成具体的类声明
	 p = new A<int,3>; //生成具体的类声明

(3)显式具体化:特定类型的类声明,用于替换模板生成的版本。因为类模板的某些操作对于特定类型并不合适,需要对这些操作进行修改。
	 具体化模板:template <> class A<int,3>{…}
	 创建对象  :A<int,3> a1(1,2); //将使用基于类模板A修改过的具体化模板,而不是通用的模板来生成具体的类声明
	 当具体化模板和通用模板都与实例化请求匹配时,编译器将使用具体化版本

(4)部分具体化:给类型参数之一指定具体的类型,template后面的<>内声明的是没有被具体化的类型参数
	 类模板    :template <class Type1,class Type2> class A{…}
	 显示具体化:template <> class A<int,int>{…}                 //将Type1、Type2具体化为int
	 1、部分具体化:template <class Type1> class A<Type1,int>{…} //将Type2具体化为int
	 2、为指针类型提供类模板的特殊版本:
	 	        template <class Type1,class Type2*> class A{…}  //将Type2具体化为指针类型
	 3、将一个类型参数具体化为另一个类型参数:
		        template <class Type1> class A<Type1,Type1>{…}  //将Type2具体化为Type1
		        template <class Type1> class A<Type1,Type1*>{…} //将Type2具体化为Type1的指针类型
	 
	 如果有多个模板可供选择,编译器将使用具体化程度最高、最匹配的模板:
	 A<double,double> a1; //使用A<Type1,Type2>
	 A<double,int> a1; //使用A<Type1,int>
	 A<double,double*> a1; //使用A<Type1,Type2*>

模板作为类成员【CppP474】

函数模板作为类模板成员:
类内声明:
template<typename T>
class A{
	public:
		 template<typename U>
	     void fun(U a,T b);
}

类外定义:
template<typename T> //类模板
	template<typename U> //函数模板
		void A<T>::fun(U a,T b){…}
————————————————————————————————————————————————————————————————————————————————————————————
类模板作为类模板嵌套类
类内声明:
template<typename T>
class A{
	private:
		 template<typename V>
	     class B;
}

类外定义:
template<typename T> //类模板
	template<typename V> //嵌套的类模板
		class A<T>::B{…}

类模板作为模板的类型参数【CppP476】

template<template<typename T> class U,typename V> //template<typename T> class代替typename;U为类型参数,是一个类模板的名
class A{
	private:
		U<int> u1; //用类模板U创建对象
		U<V> u2;
}

A<B> a1; //以类模板B为类型参数,创建对象a1
A内的U<int> u1就替换为B<int> u1,U<V> u2就替换为B<V> u2

类模板与友元函数【CppP477】

【非模板友元函数】
两步:
(1)在类内声明友元函数:
template<typename T>
class A{
	public:
		friend void fun(T a);  //注意,带有T不代表fun就是模板函数
}
(2)对于所有出现的A的具体化类型,fun()都要给出对应的具体化重载版本:
A<int> a1;
A<double> a2;
void fun(int a){…}
void fun(double a){…}
————————————————————————————————————————————————————————————————————————————————————————————
【约束模板友元函数】
类模板和函数模板一一对应,类的每种具体化都会生成对应的函数具体化
三步:
(1)类定义前面声明每个函数模板:
	 template<typename T> void fun1();
	 template<typename T> void fun2(T);
(2)类定义内将函数模板声明为友元:
	 friend void fun1<T>();
	 friend void fun2<>(T); //如果能从参数推断出fun2的类型,则可以省略<>中的T。也可以写全template<typename T> void fun2<T>(T);
(3)类外定义友元函数模板
	 template<typename T>
	 void fun1(){…}
	 template<typename T>
	 void fun2(T a){…}
————————————————————————————————————————————————————————————————————————————————————————————
【非约束模板友元函数】
多对多。类的具体化与函数的具体化相互独立
两步:
(1)类定义内声明函数模板和友元
	template<typename T>
		class A{
			public:
	 			template<typename U> friend void fun(U); //实际调用fun()时会根据参数类型自动生成具体化定义
	}
(2)类外定义友元函数模板
	template<typename U>
	void fun(U){…} 

类模板提供一系列别名【CppP482】

template<typename T>
using aa = A<T,3>; //将aa作为A<T,3>的别名
aa<int> a1; //a1为A<int,3>的对象

using= 用于非模板时:
using pin = int *; //pin作为int*的别名

二、容器

vector与array类模板【CppP99】

vector<typeName> v(n_elem); //定义一个类型为typeName的,长度为n_elem的vector对象v
(1)vector用new创建,因此存储在堆(自由存储区)中
(2)一般初始长度设置为0,利用vector包中的各种方法插入、删除值时,自动调整长度
————————————————————————————————————————————————————————————————————————————————————————————
array<typeName,n_elem> arr; //定义一个类型为typeName的,长度为n_elem的array对象arr 
(1)array对象的长度是固定的,存储在栈中(普通数组作为自动变量,也存储在栈中)
(2)n_elem不能是变量,只能填一个常数或符号常量(const int a=4;),这一点与vector不同
(3)可以用一个arr对象给另一个arr对象赋值(对象的赋值):arr1 = arr2;

三、迭代器

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值