泛型编程(generic
programming),如同面向对象OOP,核心依然是多态。OOP中主要体现在运行时的动态绑定,基类型的指针可以指向派生类对象。GP主要体现在
编译时的多态,一个类或函数可以套用多种不同的类型,标准库中的容器,迭代器和算法都是GP的体现,它们在编写时都是与类型无关的。C++中泛型编程的核
心就是模板(template)。
模板的定义前要有关键字template,和面是模板参数列表,标记在<>内
template <typename T>
int func(T c){
//...
} |
<>中的 typename T 称为模板参数(template parameter),
typename为关键字,
T其实可以被任意的合法字符串替代,<>内的模板参数至少要有一个,不能为空,模板参数也可以作为函数的返回值。
调用时,编译器将模板实参与形参绑定,实例化(instantiate)此函数模板。
如果是内联函数,则关键字
inline必须在模板参数之后,如:
template
inline func(T c)(){};
不可以写成 inline template func(T c)(){};
类模板(class template):
template
class MyClass{
public:
Type data;
//...
};
类模板是一种模板,所以必须以关键字template开头,后接模板参数。
这里Type可以作为一种类型来定义数据成员、成员函数的参数和返回值,其余模板类和普通类没有什么区别。
使用时,MyClass obj1; 编译器结合调用实参来实例化一个此模板类的实例,用int替换所有Type出现的地方。
模板参数:
模板参数的作用域与普通参数类似,会覆盖之前同名的。
typedef int T;
template func(T c){
T data;
}
当调用时如果模板实参不是int,则模板参数会覆盖全局的T,既data为调用时的模板实参类型,而不是int型。而且不可在模板参数作用域内定义与其名字相同的。例如:
template func(T c){
typedef int T;
T data;
}
编译器会报错。
template 这样也是不行的。
模板参数在声明时可以不同名字,如:
template func(T c){}
在另一文件中可以template func(U c){}
在模板内定义制定类型:
template
func(Para *array){
Para::size_type * p;
}
这里存在Para:size_type是一个数据成员还是一种类型的问题(STL中容器都有size_type),编译器默认会当做一种数据成员。如果Para:size_type是一种类型,需要在前面加上 typename。
注:类似这种情形最好都加上typename,因为当目标不是一种类型时,typename也不会发生什么。
即:typename Para::size_type * p;
模板参数中的typename与class,使用typename可以使用build-in类型当作模板参数,而某些较老的编译器只认得class模板参数.模板参数中也可以有build-in类型或已定义的类类型的。
模板非类型参数(template nontype parameter)在模板的定义域内被当做常量。
template func((T) (&Para_Array)Para_int){}
int main(void) {
int a[10],b[20];
func(a); //毫无问题
puts("end in main");
return EXIT_SUCCESS;
}
使用模板参数时一定要注意:函数体内对参数的操作一定要合法,如比较两个参数大小,如果对于该模板参数没有重载的"<"或">"运算符,运行时会出错。所以:
1.要尽可能地减少模板参数的个数。
2.参数最好为const reference 常引用。
3.使用的运算法越少越好(比较大小只使用"<"或">").
阅读(610) | 评论(0) | 转发(0) |