旅游网站建设的组织性,网站建设书籍附光盘,设计非常好的网站,推广渠道方式【本节目标】
1. 泛型编程2. 函数模板3. 类模板 目录
【本节目标】
1.泛型编程
2.函数模板
概念#xff1a;
格式#xff1a;
原理#xff1a;
实例化#xff1a;
1.隐式实例化#xff1a;
2.显式实例化
原则一#xff1a;
原则二#xff1a;
原则三#…【本节目标】
1. 泛型编程2. 函数模板3. 类模板 目录
【本节目标】
1.泛型编程
2.函数模板
概念
格式
原理
实例化
1.隐式实例化
2.显式实例化
原则一
原则二
原则三
3.类模板
格式
类模板的实例化 1.泛型编程
如何实现一个通用的交换函数呢 以下面的交换函数为例 // 交换两个整型变量
void Swap1(int p1, int p2)
{int tmp p1;p1 p2;p2 tmp;
}// 交换两个字符型变量
void Swap(char p1, char p2)
{char tmp p1;p1 p2;p2 tmp;
} 可以看到两种不同类型的交换函数的实现我们用重载函数去实现的 使用函数重载虽然可以实现但是有一下几个不好的地方
1. 重载的函数仅仅是类型不同代码复用率比较低只要有新类型出现时就需要用户自己增加对应的函数2. 代码的可维护性比较低一个出错可能所有的重载均出错 如果我们像印刷一样弄一个模具然后让编译器根据不同的类型利用该模具来生成代码呢 如果在C中也能够存在这样一个模具通过给这个模具中填充不同材料(类型)来获得不同材料的铸件(即生成具体类型的代码那将会节省许多头发。巧的是前人早已将树栽好我们只需在此乘凉。
泛型编程编写与类型无关的通用代码是代码复用的一种手段。模板是泛型编程的基础 2.函数模板
概念
函数模板代表了一个函数家族该函数模板与类型无关在使用时被参数化根据实参类型产生函数的特定类型版本。
格式
templateclass T1, class T2, ...., class Tn
返回值类型 函数名(参数列表)
{ }//templatetypename T
templateclass T
void Swap(T left, T right) {T tmp left;left right;right tmp;
}
注意typename 是用来定义模板参数关键字也可以使用 class切记不能使用 struct 代替 class
这里我们推荐使用class因为它短而且STL里面用的就是class
原理
函数模板是一个蓝图它本身并不是函数是编译器用使用方式产生特定具体类型函数的模具。
所以其实模板就是将本来应该我们做的重复的事情交给了编译器。 在编译器编译阶段对于模板函数的使用编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。
比如当用double类型使用函数模板时编译器通过对实参类型的推演将T确定为double类型然后产生一份专门处理double类型的代码对于字符类型也是如此。 实例化
用不同类型的参数使用函数模板时称为函数模板的实例化。
模板参数实例化分为隐式实例化和显式实例化。
1.隐式实例化
让编译器根据实参推演模板参数的实际类型
templateclass T
T Add(const T left, const T right)
{return left right;
}int main()
{int a1 10, a2 20;double d1 1.1, d2 2.2;Add(a1, a2); // 编译器根据实参a1和a2推演出模板参数为int类型Add(d1, d2); // 编译器根据实参d1和d2推演出模板参数为int类型return 0;
}
但是注意以下情况属于编译失败 因为a1是intd1是couble编译器无法确定此处到底该将 T 确定为 int 或者 double 类型而报错。
处理这种方式有两种方法 1用户自己来进行强制转换 templateclass T
T Add(const T left, const T right)
{return left right;
}int main()
{int a1 10, a2 20;double d1 1.1, d2 2.2;Add((double)a1, d1); // 把a1强转成doubleAdd(a1, (int)d1); // 把d1强转成intreturn 0;
}2使用个显示实例化 templateclass T
T Add(const T left, const T right)
{return left right;
}int main()
{int a1 10, a2 20;double d1 1.1, d2 2.2;Addint(a1, d1); Adddouble(a1, d1);return 0;
} 总结这个T必须是明确的 2.显式实例化
所谓显示实例化就是在函数名后的 中指定模板参数的实际类型。
templateclass T
T Add(const T left, const T right)
{return left right;
}int main()
{int a1 10, a2 20;Addint(a1, a1); return 0;
}原则一
1 一个非模板函数可以和一个同名的函数模板同时存在而且该函数模板还可以被实例化为这个非模板函数
// 专门处理int的加法函数
int Add(int left, int right)
{cout 非模板调用 endl;return left right;
}// 通用加法函数
templateclass T
T Add(T left, T right)
{cout 模板调用 endl;return left right;
}int main()
{cout Add(1, 2) endl; // 与非函数模板类型完全匹配不需要函数模板实例化cout Addint(1, 2) endl; // 模板函数可以生成更加匹配的版本编译器根据实参生成更加匹配的Add函数return 0;
} 编译器会优先去选择已经存在的函数如果没有这个函数的存在才会去用函数模板生成 原则二
2对于非模板函数和同名函数模板如果其他条件都相同在调动时会优先调用非模板函数而不会从该模板产生出一个实例。
如果模板可以产生一个具有更好匹配的函数 那么将选择模板
// 专门处理int的加法函数
int Add(int left, int right)
{cout 非模板调用 endl;return left right;
}// 通用加法函数
templateclass T
T Add(T left, T right)
{cout 模板调用 endl;return left right;
}int main()
{cout Add(1, 2) endl; // 与非函数模板类型完全匹配不需要函数模板实例化cout Add(1.1, 2.0) endl; // 模板函数可以生成更加匹配的版本编译器根据实参生成更加匹配的Add函return 0;
} 原则三
模板函数不允许自动类型转换但普通函数可以进行自动类型转换。 3.类模板
格式
类模板格式
templateclass T1, class T2, ...., class Tn
class 类模板名
{// 类成员定义
};
以一个栈的数据结构定义为例
templateclass T
class Stack
{
public:Stack(int capaicty 4):_a(new T[capaicty]),_top(0), _capacity(capaicty){}~Stack(){delete[] _a;_capacity _top 0;}private:T* _a;size_t _top;size_t _capacity;
};类模板的实例化
类模板实例化与函数模板实例化不同类模板实例化需要在类模板名字后跟 然后将实例化的类型放在 中即可。
// 跟上述栈定义的 代码
int main()
{Stackint st1; // intStackdouble st2; // doublereturn 0;
}
类模板名字不是真正的类而实例化的结果才是真正的类