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 类模板


类模板的定义

C++的类模板的写法如下:
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>完全是两个类
这两个类的对象之间不能互相赋值










郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。