在以OO为主要设计方式的语言中,C++不是第一个引入类这个概念的编程语言,但我觉得它应该是做得最成功的一个。我的理解是编程语言是一个类型系统,我们要么使用语言内置的类型,要么编写自己的类型,目的是找出恰当的抽象,在问题域和解域之间搭建桥梁。当然c++模板类,正确的抽象是不容易得到的,不过C++让我们在思考这个问题时有了更多的控制能力。
模板的初衷是想让代码的表达能够独立于类型,但类型本身的扩展性和递归性逐渐衍生出了泛型程序设计范式,对它的完善又反过来极大地推动了语言本身的扩展。C++越来越像一门全新的语言了。这一切的根基就是类模板。下面先看个简单的类模板例子
template
class Stack {
private:
T elems_[100];
public:
void push(T elem);
T pop();
};
跟函数模板一样,template引入一个类型参数列表,里面的类型参数可以用在随后声明的Stack类定义中。这个类的类型名为Stack,不过在它的定义内部,可以省略类型参数(Stack的左大括号{后面就属于Stack的名称范围之内了)
Stack(const Stack &); // Stack(const Stack &);
在类定义体的外面,你还是需要使用完整的类型名。因为你需要使用类型参数,所以还需要带上template,不过::之后就进入到了Stack的命名空间里了,T又可以省略了。
template
Stack::Stack(const Stack &other) {
for (int i = 0; i < 100; ++i) {
elems_[i] = other.elems_[i];
}
}
对于把Stack用作参数类型的函数定义,也需要template引入类型参数列表,这里没有::把你带进到Stack的命令空间里,所以T是不能省略的
template
bool operator==(const Stack &lhs, const Stack &rhs) {
for (int i = 0; i < 100; ++i) {
if (lhs.elems_[i] != rhs.elems_[i]) {
return false;
}
}
return true;
}
使用这个类模板Stack很简单,只需要告诉编译器这个T是什么类型就可以了(C++17之后,你甚至可以省略这个类型,只要它的构造函数参数能够推断出T)。
Stack stack_int;
Stack stack_str;
除了多了一个T,看起来类模板的定义和使用跟普通类没有多少差别(其实背后的操作和函数模板类似,编译器在编译时会生成Stack的int和std::string两个版本的Stack代码,里面不再有T,所有的T都被替换为int或std::string。代码实例化的过程同样也是按需实例化,不多不少,刚刚满足程序运行需要。类模板的成员函数只有被实际调用了才会生成相应的代码,否则对应版本的代码里该函数不存在)。
对于用来实例化T的类型,唯一的要求就是实际使用的操作必须是有效的。比如上面的Stack定义,内部存储为数组,这就要求T必须是可缺省创建的,基本类型都满足这个要求,对于定制的类c++模板类,它必须有缺省构造函数;拷贝构造函数的定义,使用了=操作符;operator==的定义使用了!=操作符,这些如果你在实际中用到了,那这些操作对于T必须是有效的,否则编译器会告诉你的。
限时特惠:本站每日持续更新海量设计资源,一年会员只需29.9元,全站资源免费下载
站长微信:ziyuanshu688