C++ | 高级教程 | 泛型模板
👻 概念
- 泛型编程 —— 以一种独立于任何特定类型的方式编写代码,如向量有
vector <int>
或vector <string>
- 模板 —— 泛型编程的基础,是创建泛型类或函数的蓝图或公式
👻 函数模板
👾语法格式
使用 关键字 template
声明模板
template <typename T> return_type function_name(parameter list) {
// 函数主体
}
template <typename T>
—— 声明模板参数return_type
—— 返回类型function_name
—— 名称parameter list
—— 函数参数列表
👾示例代码
template <typename T> inline T const& Max (T const& a, T const& b) {
return a < b ? b:a;
}
...
int i = 5, j = 1;
cout << "Max(i, j) = " << Max(i, j) << endl; // Max(i, j) = 5
double f1 = 5.5, f2 = 1.5;
cout << "Max(f1, f2) = " << Max(f1, f2) << endl; // Max(f1, f2) = 5.5
string s1 = "Hello", s2 = "World";
cout << "Max(s1, s2) = " << Max(s1, s2) << endl; // Max(s1, s2) = World
template <typename T> inline T const& Max (T const& a, T const& b) { return a < b ? b:a; }
inline
—— 建议编译器函数内联展开,减少调用开销(函数主体很短)&
—— 使用引用避免复制对象,提高效率const
—— 保证参数不会被修改
👻 类模板
👾语法格式
template <class T> class class_name {
// 类主体
}
template <class T> return_type class_name<T>::function_name(parameter list) {
// 类成员函数主体
}
template <class T>
—— 声明模板参数class_name
—— 类名
👾示例代码
template<class T> class Stack {
private:
vector<T> elems;
public:
bool empty() const;
void push(T const&);
void pop();
T top() const;
};
/* 为空返回真 */
template<class T> bool Stack<T>::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(); // 返回最后一个元素的副本
}
...
try {
Stack<int> intStack;
intStack.push(1);
cout << intStack.top() <<endl; // 输出 1
intStack.pop();
intStack.pop();
} catch (exception const& ex) {
cerr << "Exception: " << ex.what() << endl; // 输出 Exception: Stack<>::pop(): empty stack
return -1;
}
在类成员函数内部声明时,通常不需要指定参数名
elem
,即直接使用push(T const&)
void push(T const&);
在类成员函数外部定义时,需要指定参数名,因为是函数的具体实现部分,即
push(T const& elem)
template <class T> void Stack<T>::push(T const& elem) { ... }
在声明中省略参数名,优点:
- 简洁性:声明的目的是告诉编译器函数的签名,而不是具体的实现细节。省略可以使声明更加简洁。
- 一致性:参数名在声明中可能没有实际意义,不会被编译器使用。省略可以避免不必要的冗余。
在定义模板类的成员函数时,必须指定模板参数
Stack<T>
,确保编译器能够正确地实例化模板类,即:template <class T> void Stack<T>::pop() { ... } // 正确的,Stack<T>::pop template <class T> void Stack::pop() { ... } // 错误的,Stack::pop
关键字 const
在函数声明和定义中可以用于修饰成员函数,表示该成员函数不会修改对象的任何成员变量。这种函数称为常量成员函数
或const 成员函数
template <class T> T Stack<T>::top() const { ... }
const
成员函数
- 不修改对象的任何成员变量,使得其可以在
const
对象上调用,而不违反const
的语义const Stack<int> intStack; intStack.push(4); // 编译错误,无法调用 int top = intStack.top(); // 编译正确,只有 const 成员函数可以调用
- 不能调用非
const
成员函数,只能调用其他const
成员函数
const
对象:
- 只能调用对象的
const
成员函数。