谈c++模板编程
- 说模板编程,第一个想到的却是c++ STL的容器。STL的容器都是采用模板编程完成的,之所以称为容器,我想也是因为模板编程赋予了他多变的存储与处理对象的能力。
- 就拿set来说吧
set<int> int_set;//这样这个set就是int类型的容器了
set<std::string> string_set;//这样这个set就成了string类型的容器了
- 这完全得益于模板编程赋予代码的灵活能力。
模板函数
- 首先我们想一下,既然是模板,而且在编译的时候根据具体的类型再生成对应的代码;那么,我们是不是要一个占位啊,所以这个玩意出来了:
template <class T>
template <typename T>
- 这两种形式都可以,因为我们只是想告诉编译器,我先声明一个类型T,现在这占着一个位置,等后面我用啥类型,你再生成对应的代码。所以既然T是一个类型了,那么它就可以像其它类型一样,能在一些地方使用,比如:
template <class T>
T function_name(T a, T b)
{
return a+b;
}
在这段代码里,类型T有两种用法,也是通常的用法。
1、模板类型T作为返回值类型。
2、模板类型T作为参数类型。
模板类
- 其实上面模板函数搞懂了,大概思想就懂了,可能有些具体的写法不太一样。比如在实现类函数的时候,写的形式有点区别。
1、首先声明一个占位的类型
2、在类函数中要使用的地方使用它
3、实现类成员函数中使用它,类名后面要加上模板类型。
- 下面例子直接从网上copy的,不喜勿喷。
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
using namespace std;
template <class T>
class Stack {
private:
vector<T> elems; // 元素
public:
void push(T const&); // 入栈
void pop(); // 出栈
T top() const; // 返回栈顶元素
bool empty() const{ // 如果为空则返回真。
return elems.empty();
}
};
template <class T>
void Stack<T>::push (T const& elem)
{
// 追加传入元素的副本
elems.push_back(elem);
}
template <class T>
void Stack<T>::pop ()
{
if (elems.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
// 删除最后一个元素
elems.pop_back();
}
template <class T>
T Stack<T>::top () const
{
if (elems.empty()) {
throw out_of_range("Stack<>::top(): empty stack");
}
// 返回最后一个元素的副本
return elems.back();
}
int main()
{
try {
Stack<int> intStack; // int 类型的栈
Stack<string> stringStack; // string 类型的栈
// 操作 int 类型的栈
intStack.push(7);
cout << intStack.top() <<endl;
// 操作 string 类型的栈
stringStack.push("hello");
cout << stringStack.top() << std::endl;
stringStack.pop();
stringStack.pop();
}
catch (exception const& ex) {
cerr << "Exception: " << ex.what() <<endl;
return -1;
}
}
- 在类的声明中和上面的模板函数差不多,主要是成员函数的实现部分。
- 在成员函数的实现中,有2点要注意;
1、每个函数的实现前都要独立声明一下模板类型。
template <class T>
2、类的后面要加上模板类型。
T Stack<T>::top () const
- 至于模板函数怎么用,和容器的用法一致。
- 有啥好处呢?个人感觉代码复用真的很好用。