泛型程序设计与模板:
一种算法在实现时不指定具体要操作的数据的类型的程序设计方法。所谓"泛型"是指算法只要实现
一遍,就能适用于多种数据类型。泛型程序设计方法的好处在于能够减少重复代码的编写。
在C++中模板分为函数模板和类模板两种。
函数模板:
作用:面向对象的继承和多态机制有效的提高了程序的可重用性和可扩充性,但在可重用性的
某些方面,程序员还希望得到更多的支持,以减少重复代码的编写。
// 例如:Swap函数 void Swap(int &a, int &b){ int c = a; a = b; b = c; } void Swap(double &a, double &b){ double c = a; a = b; b = c; } template <typename T> void Swap(T &a, T &b){ T c = a; a = b; b = c; }
在编写Swap函数时,在面对不同的数据类型,我们需要编写不同的重载函数,但这些函数初处了所处理的
数据类型的不同,形式上是一模一样的,为了减少这些重复代码的编写,继承和多态明显无法解决这些问
题。因此,"模板"的概念就应运而生。
函数模板的写法:
template <typename 类型参数1,类型参数2,...>
返回值类型 模板名(形参表){
函数体;
}
typename关键字也可以用class关键字代替。
函数模板的原理:
编译器由模板自动生成函数时(实例化),会用具体的类型名对模板中所有的类型参数进行替换,其他
部分则原封不动的保留。同一个类型参数只能替换为同一种类型。编译器在编译到调用函数模板的语
句时,会根据实参的类型判断该如何替换模板中的类型参数。
编译器由模板自动生成函数(类)的过程叫做模板的实例化。有模板实例化生成的函数(类)叫做模板函数(类)。
在函数模板中,类型参数不但可以用来定义参数的类型,还能用于定义局部变量和函数模板的返回值。
#include<iostream> using namespace std; template <typename T> void Swap(T &a, T &b){ T c = a; a = b; b = c; } int main() { int a = 3, b = 4; double c = 3.0, d = 4.0; Swap(a, b); // 实例化为 void Swap(int &a, int &b)函数 Swap(c, d); // 实例化为 void Swap(double &a, double &b)函数 return 0; }
编译器对模板进行实例化时,并非只能通过模板调用语句的实参来实例化模板中的类型参数,模板调用语句
可以明确指明要把类型参数实例化为哪种类型。
模板名<实际类型参数1,实际类型参数2,...>
例如:Swap<double, double>(a, b);
当有多个函数和函数模板名字相同的情况下,一条函数调用语句的匹配顺序:
1.先找到参数完全匹配的普通函数
2.再找参数完全匹配的模板函数
3.再找实参经过自动类型转换后能匹配的普通函数
4.如果以上情况都无法找到,则报错
类模板:
类模板的写法:
template <类型参数表>
class 类模板名{
成员函数和成员变量;
};
类型参数表的写法:
class 类型参数1,class 类型参数2,...
类模板中的成员函数放到类模板外面定义时的写法:
template <类型参数表>
返回值类型 类模板名<类型参数名列表>::成员函数名(参数表){
...
}
用类模板定义对象的写法如下:
类模板名<真是类型参数表> 对象名(构造函数实际参数表);
可以将函数模板当做类模板的成员函数,成员函数模板只有在被调用时才会被实例化。
类模板的类型参数表中可以出现非类型参数
template <class T, int size>
class Carry{
};
类模板和类模板之间类模板和类之间可以相互继承,它们之间的派生关系有以下四种:
1.类模板 从 类模板 派生
2.类模板 从 模板类 派生
3.类模板 从 普通类 派生
4.普通类 从 模板类 派生
函数、类、类的成员函数、函数模板、类模板、类模板的成员函数都可以作为类模板的友元。
类模板中可以定义静态成员,给定实例化得到的所有对象共享一个静态成员。
template <class T> class Foo{
...
static int i;
}
即Foo<int>共享一个static int i,Foo(string)共享一个static int i。
当需要在多个文件中用到同一个模板,则可以将该模板的全部内容(包括类模板的成员函数的函
数体)都写在一个头文件中,然后在多个.cpp文件中包含,而不用担心重复定义的问题。
// 示例 template <class Type> class QueueItem{ QueueItem(const Type &t):item(t), next(0){ } Type item; QueueItem *next; }; template <class Type> class Queue{ private: QueueItem<Type> *head; QueueItem<Type> *tail; void destory(); void copy_elems(const Queue&); public: Queue():head(0), tail(0){ } Queue(const Queue &Q):head(0), tail(0){ copy_elems(Q); } Queue& operator=(const Queue&); ~Queue(){ destory(); } Type& front(){ return head->item; } const Type& front() const { return head->item; } void push(const Type &); void pop(); bool empty() const { return head == 0; } };
来源:https://www.cnblogs.com/lnlin/p/7661299.html