【C++的探索路17】泛型程序设计与模板之基本形式
2018-01-03 20:55
411 查看
学习内容调整
按照书中的顺序应当是输入输出流以及文件操作两部分的内容,相对来说,这两部分对我目前用途不是太大,而泛型程序设计以及后续的STL部分内容有着更高的价值,所以先跳过I/O流以及文件操作,先进行模板方面的学习与总结,后续再对剩下的这些内容进行整理。整体学习结束以后将进行一星期左右的C++习题课练习,下一步进行数据结构系列的了解与学习。
章节内容与分段
泛型程序设计
我们日常生活中接触最多的带“泛”的词语可能就是“广泛”,也就是说这是一种传播方面具备广度的行为。从字面意义上理解,泛型指的就是能广泛使用的数据类型。泛型程序设计(generic programming)是一种算法在实现时不指定具体要操作的数据类型的程序设计方法。
这种程序设计思想运用最为深度的内容就是STL(标准模板库),该部分也会在下一部分进行介绍。
整体来说,泛型程序设计带来的好处与其所起的意义,丝毫不亚于面向对象的特性。因此需要好好对这一方面进行掌握。
模板
模板为泛型程序设计中的一个基本概念,C++中,模板分为函数模板和类模板两种。熟练的C++程序员,在编写函数的时候都会考虑能否把函数编写为函数模板;在编写类的时候考虑将其编写为类模板,从而方便重用。
内容分段
书中的几个章节依据标题内容分为基本形式与细节两个部分,本篇文章对泛型程序设计与模板的基本形式内容进行学习与练习。该部分内容为函数模板以及类模板。函数模板
函数模板分为四部分进行了解,依次涉及函数模板的作用、原理、例子以及调用细节。
函数模板的作用
我们知道C++是一种很注重数据类型的语言,编写任何函数时,都需要考虑到其参数类型的匹配。虽然这样能够避免发生错误,但这也在一定程度上容易引起一些麻烦:比如我们要定义交换函数Swap对数字进行交换。
除了函数实现的主体外,还需考虑的事就是数据类型:是对double类型的数据进行交换还是int型进行交换?如果都有,很不幸,你要写两次交换函数:
#include<iostream> using namespace std; void Swap(int &a, int &b) { int tmp; tmp = a; a = b; b = tmp; cout << "int recall" << endl; } void Swap(double &a, double &b) { double tmp; tmp = a; a = b; b = tmp; cout << "double recall" << endl; } int main() { int a = 3, b = 4; cout << "a= " << a << endl << "b= " << b << endl; Swap(a, b); cout << "a b after exchange" << endl; cout << "a= " << a << endl << "b= " << b << endl<<endl; double c = 3.0, d = 4.4; cout << "c= " << c << endl << "d= " << d << endl; Swap(c, d); cout << "c d after exchange" << endl; cout << "c= " << c << endl << "d= " << d << endl << endl; return 0; }
这下你可能就会想:什么破玩意,这么搞人都会累死了;这时候你就需要模板了。
函数模板的原理
模板就是方便我们依样画葫芦,C++中分为函数模板以及类模板;这两货除了作用于不同的东西外,内容实际相同。函数模板的作用为:由你提供一个整体框架(函数体),再由编译器去完善整个细节。
定义形式
template<class 类型参数1,class 类型参数2,....>返回值类型 模板名(形参表){
函数体
}
类型参数指的是数据类型,此外class关键字也可由typename替换。
实现
编译器由模板自动生成函数时,会用具体的类型名对模板中所有的类型参数进行替换,其他部分原封不动的照抄。
template<class T> void Swap(T &a, T &b) { T tmp; tmp = a; a = b; b = tmp; } int main() { int a = 3, b = 4; cout << "a= " << a << endl << "b= " << b << endl; Swap(a, b); cout << "a b after exchange" << endl; cout << "a= " << a << endl << "b= " << b << endl << endl; double c = 3.0, d = 4.4; cout << "c= " << c << endl << "d= " << d << endl; Swap(c, d); cout << "c d after exchange" << endl; cout << "c= " << c << endl << "d= " << d << endl << endl; return 0; }
这样,就可以避免写好几个Swap进行交换了。
编译器由模板自动生成函数的过程,称为模板的实例化,由实例化得到的函数,称为模板函数。
函数模板例题---求数组中最大元素的函数模板
设计一个分数类CFraction,再设计一个名为MaxElement的函数模板,能够求数组中最大的元素,并用该模板求一个CFraction数组中的最大元素template<class T> T MaxElement(T a[], int size) { T tmpMax = a[0]; for (int i = 1; i < size; ++i) if (tmpMax < a[i]) tmpMax = a[i]; return tmpMax; } class CFraction { int numerator; int denominator; public: CFraction(int n, int d) :numerator(n), denominator(d) {}; bool operator<(const CFraction&f)const { if (denominator*f.denominator > 0) return numerator*f.denominator < denominator*f.numerator; else return numerator*f.denominator > denominator*f.numerator; } bool operator==(const CFraction&f)const { return numerator*f.denominator == denominator*f.numerator; } friend ostream&operator<<(ostream&o, const CFraction&f); }; ostream&operator<<(ostream&o, const CFraction&f) { o << f.numerator << "/" << f.denominator; return o; } int main() { int a[5] = { 1,5,3,2.4 }; CFraction f[4] = { CFraction(8,5),CFraction(-8,4),CFraction(3,2),CFraction(5,6) }; cout << MaxElement(a, 5) << endl; cout << MaxElement(f, 4) << endl; return 0; }
这部分对为什么重载==运算符不是很清楚,先行跳过。
函数或函数模板调用语句的顺序
具体内容波澜不惊,扔一张图
程序
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 Max2" << endl; return 0; } double Max(double a, double b) { cout << "Function Max" << endl; return 0; } int main() { int i = 4, j = 5; Max(1.2, 3.4); Max(i, j); Max(1.2, 3); }
程序一共定义三个Max函数,当然他们没有实现最大值返回的功能。
第一个Max函数为具备两个形参,且类型相同的函数模板。
第二个Max函数为具备两个不同类型的函数模板
第三个Max为我们常见的普通函数
在主函数中,首先定义了整型变量i,j。
第一个Max函数直接与普通函数的形参列表相同,依据首先调用普通函数原则,输出:Function Max
第二个Max为整形参数,依据模板匹配原则,输出Template Max 1
第三个Max一个参数相同,一个不同,则输出Template Max2
崩崩
知道你们喜欢看犯错,那就犯一个错吧,直接会崩溃的那种,是不是萌萌哒?下面这个程序定义了两个string类型的变量,显然没有任何一个类型可以转换成功, 那么崩吧。
template<class T,class T2> T Max(T a, T2 b) { cout << "Template Max2" << endl; return 0; } double Max(double a, double b) { cout << "Function Max" << endl; return 0; } int main() { int i = 4, j = 5; Max(1.2, 3.4); Max(i, j); Max(1.2, 3); string a="aa", b="bb"; Max(a, b); return 0; }
类模板
类模板的写法
template<类型参数表> class 类模板名{ 成员函数和成员变量 }
类模板的成员函数,在类模板定义外面编写时的语法如下:
template<类型参数表> 返回值类型 类模板名<类型参数表>::成员函数名(参数表){ 函数体 }
用类模板定义对象可以写做
类模板名<真实类型参数表>对象名(实际参数表);
如果类模板有无参构造函数,那么也可以只写:
类模板名<真实类型参数表>对象名;
Pair类模板例题
某项数据记录由两部分组成:关键字与值,其中关键字用来检索。比如,学生记录由学号和绩点注册成。程序如下:#include<string> template<class T1,class T2> class Pair { public: T1 key; T2 value; Pair(T1 k, T2 v) :key(k), value(v) {}; bool operator<(const Pair<T1, T2>&p)const; }; template<class T1,class T2> bool Pair<T1, T2>::operator<(const Pair<T1, T2>&p)const { return key < p.key; } int main() { Pair<string, int>student("Tom", 19); cout << student.key << " " << student.value; return 0; }
emmm,貌似有点复杂,逐条来看。
首先定义了一个类模板Pair,类模板内部包含成员变量key,value。构造函数Pair(T1 k,T2 v);以及重载了一个返回值为bool类型的<比较函数。
其内部需要输入一个同参数的对象,也就是Pair<T1,T2>,注意Pair<T1,T2>不是怪物而是p的类型。
在外部调用的时候也要同等对待。
主函数基本啥也没做,就起了个输出的作用。
函数模板作为类模板成员
类模板中的成员函数还可以是一个函数模板。成员函数模板只有在调用时,才会被实例化。template<class T> class A { public: template<class T2> void Func(T2 t) { cout << t; } }; int main() { A<int >a; a.Func('K'); return 0; }
总结
类模板与函数模板为泛型编程中最直接、最基本的体现,这两种技术均利用了代码的重用性,能够在一定程度上减少代码的使用量。其基本形式都差不太多,比如函数模板的形式为:
template<class T1, class T2...>
T1 function(T2 a, T3 b...){
}
类模板的形式为
template<class T1, class T2,.....>
class CLASSName{
public:
T1 a;
T2 b;
}
利用类型进行传参。
要记住,泛型编程是针对类型的编程,是为了减少写类型带来的麻烦现象。只要把它当做类型就好了
相关文章推荐
- 【C++的探索路18】泛型程序设计与模板之细节
- 【C++的探索路19】泛型程序设计与模板之练习题
- C++ 泛型程序设计 模板
- C#和Java的泛型、C++模板、C#的constraints特性以及弱类型化和强类型化的问题(转)
- ** 文件操作与模板 编程题#4: 字符串操作(Coursera 程序设计与算法 专项课程3 C++程序设计 郭炜、刘家瑛;OpenJudge)
- Java 中的泛型与 C++ 模板的比较
- C++ 面向对象程序设计上机练习二(函数模板)
- 泛型服务层基本模板
- C++模板和泛型
- C++泛型与模板
- 8、泛型程序设计与c++标准模板库2.5容器适配器
- C++基本语法3--C++程序设计教程/钱能主编--清华大学出版社
- [C++程序设计]函数模板
- C++ 有关string类的基本语法以及一个简单算法 理论加案例的形式
- 我的C++第二篇 基本控制结构程序设计
- C++模板实现泛型链表
- C++ 模板和 C# 泛型之间的区别
- C++中的泛型程序设计---函数模板
- C++程序设计_part 3 数据结构 chap15 模板
- 转 C++ 面向对象程序设计的基本特点