第 9章 多态性
9.1 函数模板
9.2 模板函数的覆盖
9.3 类模板
9.1 函数模板
1,问题的提出重载函数 可以解决功能相同或相似的函数 使用同一个函数名的问题。
void swap(char &x,char &y)
{
char t =x;
x = y;
y = t;
}
void swap(int &x,int &y)
{
int t =x;
x = y;
y = t;
}
第 9章 模板
void swap(float &x,float &y)
{
float t =x;
x = y;
y = t;
}
实际代码量并未减少。可使用函数模板减少大量代码。
9.1 函数模板
2,函数模板的定义
template <class T> 或类型名 函数名(参数表)
{
函数体
}
函数模板 就像是一个带有 类型参数 的函数 (参数 T即为类型 ),
编译程序会根据实际参数的类型确定参数的类型。
第 9章 模板
template <typename T>
类型名 函数名(参数表)
{
函数体
}
例 9.1 定义用于变量交换的函数模板
#include <iostream.h>
template <class T>
void swap(T &x,T &y)
{
T temp=x;
x=y;
y=temp;
}
void main(void)
{
char a='A',b='B';
int c=123,d=456;
double x=12.3,y=45.6;
swap(a,b);
swap(c,d);
swap(x,y);
cout << a << "," << b << endl;
cout << c << "," << d << endl;
cout << x << "," << y << endl;
}
第 9章 模板程序运行结果为:
B,A
456,123
45.6,12.3
T本身是一个类型参数,在调用函数 swap()时,编译程序会根据实际参数的类型确定 T的类型。
例 9.2 插入排序函数模板,使用插入排序函数模板可以为不同数据类型的数组排序,如整型、字符型、实型等等,为了使程序具有通用性,设计函数模板 InsertionSort()。
插入排序的基本思想:每一步将一个待排序的元素按其关键字值的大小插入到已排序序列的合适位臵,直到待排序元素全部插入完为止 。
第 9章 模板例 9.2 (续一)
template <class T>
void InsertionSort(T A[],int n)
{
int i,j;
T temp;
for (i = 1; i < n; i++)
{
//从 A[i-1]开始向 A[0]方向扫描各元素,寻找适当位臵插入 A[i]
j = i;
temp = A[i];
while (j > 0 && temp < A[j-1])
{
//当遇到 temp>=A[j-1]结束循环时,j便是应插入的位臵
//当遇到 j==0结束循环时,则 0是应插入的位臵。
A[j] = A[j-1]; //将元素逐个后移,以便找到插入位臵时可立即插入。
j--;
}
A[j] = temp;
}
}
第 9章 模板例 9.2 (续二)
#include <iostream.h>
void main()
{
int a[10]={2,4,1,8,7,9,0,3,5,6};
double b[10]={12.1,24.2,15.5,81.7,2.7,5.9,40.3,33.3,25.6,4.6};
InsertionSort(a,10);
InsertionSort(b,10);
cout << a[0] << " " << a[1]<< " " << a[2] << " " << a[3] << " ";
cout << a[4] << " " << a[5]<< " " << a[6] << " " << a[7] << " ";
cout << a[8] << " " << a[9]<< endl;
cout << b[0] << " " << b[1]<< " " << b[2] << " " << b[3] << " ";
cout << b[4] << " " << b[5]<< " " << b[6] << " " << b[7] << " ";
cout << b[8] << " " << b[9]<< endl;
}
第 9章 模板程序运行结果为:
0 1 2 3 4 5 6 7 8 9
2.7 4.6 5.9 12.1 15.5 24.2 25.6 33.3 40.3 81.7
例 9.3 使用函数模板产生的二意性
#include <iostream.h>
template <class T>
T max(T a,T b)
{
return a>b?a:b;
}
void main(void)
{
int a = max(10.5,20);
double b = max(10,20.6);
cout << a << endl;
cout << b << endl;
}
第 9章 模板产生二意性,系统不能确定将其中的一个参数由整数转化为实数,还是应该将另一个参数由实数转化为整数 。
可使用强制类型转换解决:
int a =max( (int)10.5,20);
double b =max( (double ) 10,20.6);
返 回
9.2 模板函数的覆盖下列函数模板:
template <class T>
T max(T a,T b)
{
retum a>b?a:b;
}
对于简单的数据类型,如 整型、实型、字符型 数据,这个模板能够正常工作。对于 字符串,用上述模板就会 出现问题,因为对于字符串,不能使用运算符,>”,要为其编写独立的 max()函数。
我们将函数模板生成的函数称为 模板函数 。如果某一函数的函数原型与函数模板生成的函数(模板函数)原型一致,称该函数为模板函数的 覆盖函数 。
第 9章 模板例 9.4 模板函数的覆盖
#include <string.h>
#include <iostream.h>
template <class T>
T max(T a,T b)
{
return a>b?a:b;
}
char *max(char *x,char *y)
{
return strcmp(x,y) > 0? x,y;
}
void main(void)
{
char *p="ABCD",*q="EFGH";
p=max(p,q);
int a =max(10,20);
float b =max(10.5,20.6);
cout << p << endl;
cout << a << endl;
cout << b << endl;
}
第 9章 模板程序运行结果为:
EFGH
20
20.6
9.2 模板函数的覆盖在进行函数调用时,编译程序采用如下策略确定调用哪个函数:
( 1)首先寻找一个实参与形参完全匹配的 覆盖函数,如果找到,
则调用该函数.
( 2)如果能通过 函数模板生成实例函数,并且参数匹配,则调用该函数。
( 3)通过 强制类型转换,寻找能够与实参匹白的覆盖函数,或通过函数模板生成的实例函数、如果找到则调用该函数。
( 4)如果所有努力失败,则给出出错信息。
第 9章 模板返 回
9.3 类模板
1,问题的提出
class A
{
int i;
public:
A(int a) {…}
void set (int b)
{……}

};
class B
{
double i;
public:
B(double a) {…}
void set (double b)
{……}

};
第 9章 模板对应的类模板:
template <class T>
class A
{
T i;
public:
A(T a) {…}
void set (T b)
{……}

};
这两个类的方法都一样,只是一个数据类型是整型,另一个数据类型是实型。可以使用类模板简化代码类模板也称为参数化的类,用于为类型相似的类定义一种通用模式
9.3 类模板
2,类模板的定义
template <模板参数表 >
class 类模板名
{
成员声明
}
如果需要在类模板外定义类模板的成员函数,格式如下:
template <模板参数表 >
类型 类模板名 <参数 >::函数名(参数表)
{
函数体
}
第 9章 模板
9.3 类模板
2,类模板的定义(续)
使用类模板建立对象的语法如下:
类模板 <实参表 > 对象 1,对象 2,… ;
系统会根据实参的类型,生成一个类(称为 模板类 ),然后建立该类的对象。即对模板实例化生成类,再对类实例化生成对象。
第 9章 模板例 9.5 定义数组类的类模板,并利用成员函数对数组中的元素初始化。
#include <iostream.h>
template <class T>
class myArray
{
public:
myArray(int nSize,T Initial);
~myArray()
{
delete[] m_pArray;
}
T &operator[](int nIndex) //重载运算符 []用于取得数组的元素
{
return m_pArray[nIndex];
}
void Show(int nNumElems,char *pszMsg=" ",bool bOneLine=true);
void Sort(int nNumElems);
protected:
T *m_pArray; //保存数组起始地址
int m_nSize; //数组的长度
};
第 9章 模板例 9.5 (续一)
template<class T>
myArray< T >::myArray(int nSize,T InitVal)
{
m_nSize=(nSize>1)? nSize:1;
m_pArray=new T[m_nSize];
for(int i=0;i<m_nSize;i++)
m_pArray[i]=InitVal;
}
template<class T>
void myArray< T >::Show(int nNumElems,char *pszMsg,bool bOneLine)
{
cout << pszMsg<<endl;
if(bOneLine)
{
for(int i=0;i<nNumElems;i++)
cout << m_pArray[i] << ' ';
cout << endl;
}
else
{
for(int i=0;i<nNumElems;i++)
cout << m_pArray[i]<<endl;
}
}
第 9章 模板构造函数为 m_nSize赋值,并为数组申请存储空间,将数组的每个元素都赋值为 InitVal。
成员函数 Show()显示数组元素的值,元素的个数由第一个参数指定,第二个参数为输出数组元素值之前,输出的提示信息,
第三个参数确定数组元素是显示在一行上,还是多行。
例 9.5 (续二)
template<class T>
void myArray< T >::Sort(int nNumElems)
{
int i,j;
T temp;
for (i = 1; i < nNumElems; i++)
{
j = i;
temp = m_pArray[i];
while (j > 0 && temp < m_pArray[j-1])
{
m_pArray[j] = m_pArray[j-1];
j--;
}
m_pArray[j] = temp;
}
}
第 9章 模板成员函数 Sort()使用插入排序法对数组元素排序(升序),其参数是数组中元素的个数。
例 9.5 (续三)
void main()
{
int nArr[10]={89,34,32,47,15,81,78,36,63,83};
int cArr[10]={'C','W','r','Y','k','J','X','Z','y','s'};
myArray<int> IntegerArray(10,0);
myArray<char> CharArray(10,' ');
for(int i=0;i<10;i++)
IntegerArray[i]=nArr[i];
for(i=0;i<10;i++)
CharArray[i]=cArr[i];
IntegerArray.Show(10,"Unsorted array is,");
IntegerArray.Sort(10);
IntegerArray.Show(10,"Sorted array is,");
cout << endl ;
CharArray.Show(10,"Unsorted array is,");
CharArray.Sort(10);
CharArray.Show(10,"Sorted array is,");
cout << endl;
}
第 9章 模板定义了两个类模板对象,分别为 int型和
char型,数组元素分别被初始化为 0和空格程序运行结果为:
Unsorted array is:
89 34 32 47 15 81 78 36 63 83
Sorted array is:
15 32 34 36 47 63 78 81 83 89
Unsorted array is:
C W r Y k J X Z y s
Sorted array is:
C J W X Y Z k r s y
例 9.6 使用缺省参数定义数组的类模板
#include <iostream.h>
template <class T=int>
class Array
{
T *data;
int size;
public:
Array(int);
~Array();
T &operator[](int);
};
第 9章 模板
template <class T>
Array <T>::Array(int n)
{
data = new T[size=n];
}
template <class T>
Array <T>::~Array()
{
delete data;
}
template <class T>
T &Array <T>::operator[](int i)
{
return data[i];
}
注意:函数模板不能定义缺省参数,而类模板却可以定义缺省参数。
例 9.6 (续)
void main(void)
{
int i;
Array < > L1(10); //等价于 Array <int> L1(10)
Array <char> L2(20);
for(i=0; i<10; i++)
L1[i] = i;
for(i=0; i<20; i++)
L2[i] = 'A'+i;
for(i=0; i<10; i++)
cout << L1[i] << " ";
cout << endl;
for(i=0; i<20; i++)
cout << L2[i] << " ";
cout << endl;
}
第 9章 模板程序运行结果为:
0 1 2 3 4 5 6 7 8 9
A B C D E F G H I J K L M N O P Q R S T
例 9.7 折半查找函数模板第 9章 模板基本思想:对于已按关键字排序的序列,经过一次比较,可将序列分割成两部分,然后只在有可能包含待查元素的一部分中继续查找,并根据试探结果继续分割,逐步缩小查找范围,直至找到或找不到为止。
比如在如下数组中查找值为 48的元素:
例 9.7 (续一)
template <class T>
int BinSearch(T list[],int n,T key)
{
int mid,low,high;
T midvalue;
low=0;
high=n-1;
while (low <= high) // low <= high表示整个数组尚未查找完
{
mid = (low+high)/2; // 求中间元素的下标
midvalue = list[mid]; // 取出中间元素的值
if (key == midvalue)
return mid; // 若找到,返回下标
else if (key < midvalue)
high = mid-1; // 若 key < midvalue将查找范围缩小到数组的前一半
else
low = mid+1; // 否则将查找范围缩小到数组的后一半
}
return -1; // 没有找到返回 -1
}
第 9章 模板例 9.7 (续二)
#include <iostream.h>
template <class T>
int BinSearch(T list[],int n,T key);
void main()
{
int a[10] = {2,3,7,12,16,35,67,68,90,98};
char c[11] = "abcdhijklm";
char c1='f';
int i = BinSearch(a,10,35);
int j = BinSearch(a,10,36);
int k = BinSearch(c,10,'f');
int l = BinSearch(c,10,'k');
cout << i <<"," << j <<"," << k <<"," << l << endl;
}
第 9章 模板程序运行结果为:
5,-1,-1,7
返 回谢 谢!