PKU C++程序设计实习 学习笔记4 文件操作和模板
第七章 文件操作和模板
7.1 文件操作
7.2 函数模板
泛型程序设计(Generic Programming)
算法实现时不指定具体要操作的数据的类型
泛型——算法实现一遍,适用于多种数据结构
两种类型
- 函数模板
- 类模板
函数模板
template<class 类型参数1, class 类型参数2, … > 返回值类型 模板名 (形参表) { 函数体 }例子,交换两个变量值的函数模板
template <class T> void Swap(T & x,T & y) { T tmp = x; x = y; y = tmp; } int main(){ int n = 1, m = 2; Swap(n, m); //编译器自动生成 void Swap(int &, int &)函数 double f = 1.2, g = 2.3; Swap(f, g); //编译器自动生成 void Swap(double &, double &)函数 return 0; }函数模板可以重载,只要它们的形参表不同即可
下面两个模板可以同时存在:
template<class T1, class T2> void print(T1 arg1, T2 arg2) { cout<< arg1 << " "<< arg2<<endl; } template<class T> void print(T arg1, T arg2) { cout<< arg1 << " "<< arg2<<endl; }C++编译器遵循以下优先顺序:
- Step 1: 先找参数完全匹配的普通函数(非由模板实例化而得的函数)
- Step 2: 再找参数完全匹配的模板函数
- Step 3: 再找实参经过自动类型转换后能够匹配的普通函数
- Step 4: 上面的都找不到,则报错
template <class T> T Max(T a, T b) { cout << "Template Max 1" <<endl; return 0; } template <class T, class T2> T Max(T a, T2 b) { cout << "Template Max 2" <<endl; return 0; } double Max(double a, double b){ cout << "MyMax" << endl; return 0; } int main() { int i=4, j=5; Max(1.2,3.4); //调用Max(double, double)函数 Max(i, j); //调用第一个T Max(T a, T b)模板生成的函数 Max(1.2, 3); //调用第二个T Max(T a, T2 b)模板生成的函数 return 0; }赋值兼容原则引起函数模板中类型参数的二义性
template<class T> T myFunction(T arg1, T arg2) { cout<<arg1<<“ ”<<arg2<<“\n”; return arg1; } … myFunction(5, 7); //ok: replace T with int myFunction(5.8, 8.4); //ok: replace T with double myFunction(5, 8.4); //error: replace T with int or double? 二义性可以在函数模板中使用多个类型参数, 可以避免二义性
template<class T1, class T2> T1 myFunction( T1 arg1, T2 arg2) { cout<<arg1<<“ ”<<arg2<<“\n”; return arg1; } … myFunction(5, 7); //ok:replace T1 and T2 with int myFunction(5.8, 8.4); //ok: replace T1 and T2 with double myFunction(5, 8.4); //ok: replace T1 with int, T2 with double
7.3 类模板
类模板的定义
template <类型参数表> class 类模板名 { 成员函数和成员变量 };类型参数表的写法就是:
class 类型参数1, class 类型参数2, …类模板里的成员函数,若在类模板外面定义时:
template <型参数表> 返回值类型 <span style="color:#3333ff;">类模板名<类型参数名列表></span>::成员函数名(参数表) { …… }用类模板定义对象的写法如下:
类模板名 <真实类型参数表> 对象名(构造函数实际参数表);如果类模板有无参构造函数, 那么也可以只写:
类模板名 <真实类型参数表> 对象名;示例
//Pair类模板: template <class T1, class T2> class Pair{ public: <span style="white-space:pre"> </span>T1 key; //关键字 <span style="white-space:pre"> </span>T2 value; //值 <span style="white-space:pre"> </span>Pair(T1 k,T2 v):key(k),value(v) { }; <span style="white-space:pre"> </span>bool operator < (const Pair<T1,T2> & p) const; }; template<class T1,class T2> bool Pair<T1,T2>::operator<( const Pair<T1, T2> & p) const //Pair的成员函数 operator < { return key < p.key; } //Pair类模板的使用: int main() { Pair<string, int> student("Tom",19); //实例化出一个类 Pair<string, int> cout << student.key << " " << student.value; return 0; } 输出结果: Tom 19
使用类模板声明对象
- 编译器自动用具体的数据类型,替换类模板中的类型参数,生成模板类的代码
由类模板实例化得到的类叫模板类
- 为类型参数指定的数据类型不同, 得到的模板类不同
Pair<string, int> * p; Pair<string, double> a; p = & a; //wrong
函数模版作为类模板成员
#include <iostream> using namespace std; template <class T> class A{ public: template<class T2> void Func(T2 t) { cout << t; } //成员函数模板 }; int main() { A<int> a; a.Func('K'); //成员函数模板 Func被实例化 return 0; } 程序输出: K要注意,类模板的类型参数,和成员函数模板的类型参数,是不能一致的。
若函数模板改为template <class T>void Func(T t){cout<<t}将报错 “declaration of ‘class T’shadows template parm ‘class T’ ”
类模板与非类型参数
类模板的参数声明中可以包括非类型参数,如:template <class T, int elementsNumber>
- 非类型参数:用来说明类模板中的属性
- 类型参数:用来说明类模板中的属性类型,成员操作的参数类型和返回值类型
template <class T, int size> class CArray{ T array[size]; public: void Print( ) { for(int i = 0; i < size; ++i) cout << array[i] << endl; } }; CArray<double, 40> a2; CArray<int, 50> a3; 注意: CArray<int,40>和CArray<int,50>完全是两个类 这两个类的对象之间不能互相赋值
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。