参考书 <C++ By Dissection>
In C++, there are 3 different ways to employ generic coding techniques:
void* pointers,
Templates,
Inheritance.
一、为什么使用模板进行泛型编程更好
举例:通用数组拷贝
方法一、二:使用void* 和 template
可以用void*或template来实现“通用数组拷贝 ”,但是后者 有以下优势——
(1)按元素拷贝,不依赖平台,增强可移植性 。
void*因为不知道每个元素的大小elementSize,只能将elementSize作为参数传入,但C++中类型的长度依赖平台,因此移植性不好。
(2)若源和目的数组类型不同,提供类型保护 (编译时报错unification error)。
void*不能满足这个要求。
#include <iostream> using namespace std; //ordinary int transfer1(int from[], int to[], int size){ for(int i=0;i<size;i++){ to[i]=from[i]; } return size; } //void* generic assignment function int transfer2(void* from, void* to, int elementSize, int size){ int nBytes=elementSize*size; for(int i=0;i<nBytes;i++){ static_cast<char*>(to)[i]=static_cast<char*>(from)[i]; } return size; } //template generic assignment function template<class T> int transfer3(T* from, T* to, int size){ for(int i=0;i<size;i++){ to[i]=from[i]; } return size; } template<class T> void printArr(T from[], int size){ for(int i=0;i<size;i++) cout<<from[i]<<"\t"; cout<<endl; } int main(void){ int a[10]={1,2,3,4,5,6,7,8,9,10},b[10]; double c[20]={10,9,8,7,6,5,4,3,2,1},d[20]; transfer1(a,b,10); printArr(b,10); //使用void* 只能逐字节拷贝 transfer2(c,d,8,10); printArr(d,10); //使用模板,可以仍然逐元素拷贝 d[1]++; transfer3(d,c,10); printArr(c,10); //相比void*,template仍然提供类型保护(type-safety) transfer3(a,c,10); //报错 transfer2(a,c,4,10); //不报错 system("pause"); return 0; }
方法三:使用宏定义
我来评价一下宏定义实现泛型编程的优势和劣势——
(1)宏定义优势:
简单性(Simplicity)、习惯性(familiarity)、高效性(Efficiency)。
其中,习惯性是由于在C编程中使用宏(macros)的传统;高效性主要因为没有函数调用的开销。
(2)宏定义劣势:
没有类型保护(type-safety)、预期外的计算(unanticipated evaluations)、范围问题(Scoping problem)
其中,与使用模板对比,解释一下“预期外的计算”。例如,计算立方,
可以使用宏
#define CUBE(X) ((X)*(X)*(X))
可以使用模板
template<class T> T cube(T x) {return x*x*x;}
现在需要计算(sqrt(7))³
如果使用宏,CUBE(sqrt(7)),因为是直接文本替换,计算了三次sqrt(7);
如果使用函数,cube(sqrt(7)),则只调用一次sqrt(7)。
这样一来,虽然宏没有函数调用的开销(使用对战的机制),但是重复的计算使得它的优势得不偿失:(
#include <iostream> using namespace std; #define COPY(A,B,N)\ {int i; \ for(i=0;i<(N);++i) (B)[i]=(A)[i];} template<class T> void printArr(T from[], int size){ for(int i=0;i<size;i++) cout<<from[i]<<"\t"; cout<<endl; } int main(void){ int a[10]={1,2,3,4,5,6,7,8,9,10},b[10]; double c[20]={10,9,8,7,6,5,4,3,2,1},d[20]; COPY(a,b,10); printArr(b,10); system("pause"); return 0; }
二、使用模板
1. Template Class 模板类
2. Function Templates 函数模板
Many functions have the same code body, regardless of type(例如上面的例子)