目录
一、引言
在编程的世界里,C++ 以其强大的功能和高效的性能著称,而类模板(Class Template)则是 C++ 中一项极为重要的特性。想象一下,你手中有一把神奇的万能模具,它可以制作出各种不同形状和材质的物品,比如用它可以制作塑料玩具、金属零件,只要你提供相应的材料。C++ 的类模板就如同这把万能模具,它能够根据不同的数据类型,生成具有相同逻辑结构的类,大大提高了代码的复用性和灵活性。接下来,就让我们一起深入探索 C++ 类模板的奥秘。
二、类模板初相识
(一)定义与语法
在 C++ 中,类模板的定义需要使用 template 关键字,其后跟着尖括号 <>,尖括号内是类型参数列表。每个类型参数前通常使用 typename 关键字(也可以使用 class,二者在这里功能相同)来声明这是一个类型参数。例如,定义一个简单的类模板 MyClass,它有一个类型为 T 的成员变量和一个成员函数:
template <typename T>
class MyClass {
private:
T data;
public:
MyClass(T value) : data(value) {}
void print() {
std::cout << "The value is: " << data << std::endl;
}
};
在这个例子中,T 就是类型参数,它可以在类模板被实例化时被替换为任何合法的数据类型,比如 int、float、std::string 等。当我们使用 MyClass 类模板创建对象时,需要明确指定 T 的具体类型,如 MyClass<int> obj(10);,这样就创建了一个 MyClass 类模板的实例,其中 T 被替换为 int 类型 。
(二)与普通类的区别
普通类在定义时,其成员变量和成员函数所涉及的数据类型都是明确固定的。例如下面这个普通的 Point 类:
class Point {
private:
int x;
int y;
public:
Point(int a, int b) : x(a), y(b) {}
void print() {
std::cout << "x = " << x << ", y = " << y << std::endl;
}
};
它只能处理 int 类型的坐标值。
而类模板则具有类型参数化的特点,它的成员变量和成员函数的数据类型是由实例化时指定的类型参数决定的。以之前的 MyClass 类模板为例,它可以根据不同的类型参数 T 被实例化为不同的具体类,从而处理不同类型的数据。
另外,在类模板中,如果成员函数在类外定义,其语法也与普通类不同。例如,将 MyClass 类模板的 print 函数在类外定义:
template <typename T>
void MyClass<T>::print() {
std::cout << "The value is: " << data << std::endl;
}
需要在函数定义前加上 template <typename T> 声明这是一个类模板相关的函数,并且类名要写成 MyClass<T> 的形式,以表明该函数是属于类模板 MyClass 的,而普通类的成员函数在类外定义时不需要这样的模板声明 。
三、类模板使用全攻略
(一)简单示例展示
让我们通过一个具体的例子来深入理解类模板的使用方法。下面定义了一个 Stack 类模板,用于实现一个简单的栈结构:
template <typename T>
class Stack {
private:
T* data;
int top;
int capacity;
public:
Stack(int cap = 10) : capacity(cap), top(0) {
data = new T[capacity];
}
~Stack() {
delete[] data;
}
void push(T value) {
if (top >= capacity) {
// 简单处理栈满情况,这里可以进行扩容操作
return;
}
data[top++] = value;
}
T pop() {
if (top <= 0) {
// 简单处理栈空情况,这里可以抛出异常
return T();
}
return data[--top];
}
bool isEmpty() {
return top == 0;
}
};
使用这个 Stack 类模板创建对象并调用其成员函数的方式如下:
int main() {
Stack<int> intStack;
intStack.push(10);
intStack.push(20);
while (!intStack.isEmpty()) {
std::cout << intStack.pop() << " ";
}
std::cout << std::endl;
Stack<std::string> stringStack;
stringStack.push("Hello");
stringStack.push("World");
while (!stringStack.isEmpty()) {
std::cout << stringStack.pop() << " ";
}
std::cout << std::endl;
return 0;
}
在上述代码中,首先创建了一个 Stack<int> 对象 intStack,用于存储整数类型的数据。通过调用 push 函数将整数 10 和 20 压入栈中,然后使用 pop 函数将栈中的元素弹出并打