类模板的核心作用是实现泛型编程,通过template定义通用类骨架,根据传入类型自动生成具体类,提升代码复用性。例如MyPair模板可实例化为不同类型的配对类,在编译时生成对应代码,确保类型安全并避免重复。与函数模板侧重算法不同,类模板关注数据结构的通用化,适用于容器、智能指针等场景。非类型模板参数(如size_t Capacity)允许在编译时固定常量配置,增强性能和安全性。类模板特化则针对特定类型提供定制实现,分为全特化和偏特化,用于优化特殊类型的行为或提升效率。

C++中,类模板的核心作用是让我们能够编写与具体数据类型无关的通用类。说白了,就是定义一个类的“骨架”,这个骨架可以根据你传入的不同数据类型(比如
int
double
要实现一个通用类,我们首先需要用
template
<typename T>
<class T>
T
我们以一个简单的“配对”(Pair)类为例,它能存储两个任意类型的值:
#include <iostream>
#include <string>
// 声明一个类模板
template <typename T1, typename T2>
class MyPair {
private:
T1 first;
T2 second;
public:
// 构造函数
MyPair(T1 f, T2 s) : first(f), second(s) {}
// 获取第一个元素
T1 getFirst() const {
return first;
}
// 获取第二个元素
T2 getSecond() const {
return second;
}
// 设置第一个元素
void setFirst(T1 f) {
first = f;
}
// 设置第二个元素
void setSecond(T2 s) {
second = s;
}
// 打印配对内容
void print() const {
std::cout << "Pair: (" << first << ", " << second << ")" << std::endl;
}
};
// 成员函数也可以在类外定义,但需要再次使用 template 声明
// template <typename T1, typename T2>
// void MyPair<T1, T2>::print() const {
// std::cout << "Pair: (" << first << ", " << second << ")" << std::endl;
// }
int main() {
// 实例化一个存储int和double的MyPair
MyPair<int, double> p1(10, 20.5);
p1.print(); // 输出: Pair: (10, 20.5)
// 实例化一个存储string和char的MyPair
MyPair<std::string, char> p2("Hello", 'W');
p2.print(); // 输出: Pair: (Hello, W)
// 实例化一个存储两个int的MyPair
MyPair<int, int> p3(100, 200);
p3.setFirst(101);
std::cout << "New first value: " << p3.getFirst() << std::endl; // 输出: New first value: 101
return 0;
}在上面的例子中,
MyPair
T1
T2
MyPair<int, double> p1
int
double
MyPair
first
int
second
double
立即学习“C++免费学习笔记(深入)”;
在我接触C++模板的初期,很多人都容易把类模板和函数模板混为一谈,觉得它们都是
template
函数模板,顾名思义,是针对函数的。它允许我们编写一个通用的函数定义,这个函数可以操作不同类型的数据。比如
std::swap
std::max
int
double
template <typename T>
T add(T a, T b) {
return a + b;
}
// 调用时:add(1, 2) -> T被推导为int
// add(1.5, 2.3) -> T被推导为double而类模板,则关注于数据结构或类的整体行为。它允许我们定义一个通用的类,这个类可以包含各种类型的成员变量,并提供操作这些成员的通用方法。比如
std::vector
std::list
std::map
std::vector<int>
核心差异总结一下:
最佳实践方面:
在我看来,选择哪种模板,更多的是看你抽象的是“行为”还是“结构”。如果只是一个简单的行为,用函数模板就够了;如果涉及到复杂的数据组织和管理,那类模板无疑是更合适的选择。
除了类型参数(如
typename T
int
size_t
我们来看一个常见的例子:实现一个固定大小的数组。如果用类型模板参数,我们只能定义数组元素的类型,但数组的大小就得通过构造函数传入,或者用
std::vector
#include <iostream>
#include <array> // C++标准库的std::array就是非类型模板参数的典型应用
// 定义一个固定大小的栈
template <typename T, size_t Capacity> // T是类型参数,Capacity是非类型参数
class FixedStack {
private:
std::array<T, Capacity> data; // 使用std::array作为底层存储
size_t top; // 栈顶指针
public:
FixedStack() : top(0) {} // 构造函数初始化栈顶
bool push(const T& value) {
if (top < Capacity) {
data[top++] = value;
return true;
}
std::cerr << "Stack overflow!" << std::endl;
return false;
}
T pop() {
if (top > 0) {
return data[--top];
}
std::cerr << "Stack underflow!" << std::endl;
// 实际项目中这里可能抛出异常
return T{}; // 返回默认构造的值
}
bool isEmpty() const {
return top == 0;
}
bool isFull() const {
return top == Capacity;
}
size_t size() const {
return top;
}
size_t capacity() const {
return Capacity; // 可以通过成员函数获取编译时确定的容量
}
};
int main() {
// 实例化一个存储int,容量为5的栈
FixedStack<int, 5> intStack;
intStack.push(10);
intStack.push(20);
std::cout << "Popped: " << intStack.pop() << std::endl; // 输出: Popped: 20
std::cout << "Stack capacity: " << intStack.capacity() << std::endl; // 输出: Stack capacity: 5
// 实例化一个存储std::string,容量为3的栈
FixedStack<std::string, 3> stringStack;
stringStack.push("Apple");
stringStack.push("Banana");
stringStack.push("Cherry");
stringStack.push("Date"); // Stack overflow!
std::cout << "Popped: " << stringStack.pop() << std::endl; // 输出: Popped: Cherry
return 0;
}在这个
FixedStack
Capacity
FixedStack<int, 5>
FixedStack<int, 10>
非类型模板参数的有效管理和使用技巧:
int
size_t
std::array
std::array
std::vector
using
我个人认为,非类型模板参数是C++在性能和抽象之间取得平衡的一个巧妙设计。它允许我们在编译阶段就锁定一些关键特性,从而避免了运行时的开销,这对于追求极致性能的系统来说至关重要。
当我们在使用类模板时,有时会遇到一个问题:对于某些特定的数据类型,通用的模板实现可能不够高效,甚至会产生错误,或者我们希望它有完全不同的行为。这时候,类模板特化(Template Specialization)就派上用场了。它允许我们为模板的某个或某些特定类型参数提供一个完全独立的实现。
特化可以分为两种:全特化(Full Specialization)和偏特化(Partial Specialization)。
全特化:当你为模板的所有类型参数都指定了具体类型时,就是全特化。这意味着你为某个特定的类型组合提供了一个全新的类定义。
#include <iostream>
#include <string>
#include <vector>
// 通用模板定义
template <typename T>
struct Printer {
void print(const T& val) {
std::cout << "Generic print: " << val << std::endl;
}
};
// 对 `const char*` 类型进行全特化
template <> // 注意这里的 <>,表示所有模板参数都已确定
struct Printer<const char*> {
void print(const char* val) {
// 对于字符串指针,我们希望打印其内容,而不是指针地址
std::cout << "String literal print: " << (val ? val : "(null)") << std::endl;
}
};
// 对 `std::vector<bool>` 类型进行全特化(虽然标准库已经有,这里做个示例)
// std::vector<bool> 是一个特殊优化过的模板,它的元素不是独立的bool,而是位域
template <>
struct Printer<std::vector<bool>> {
void print(const std::vector<bool>& vec) {
std::cout << "Vector<bool> print: [";
for (size_t i = 0; i < vec.size(); ++i) {
std::cout << (vec[i] ? "true" : "false") << (i == vec.size() - 1 ? "" : ", ");
}
std::cout << "]" << std::endl;
}
};
int main() {
Printer<int> intPrinter;
intPrinter.print(123); // 调用通用模板
Printer<double> doublePrinter;
doublePrinter.print(45.67); // 调用通用模板
Printer<const char*> stringPrinter;
stringPrinter.print("Hello Template!"); // 调用 `const char*` 的全特化版本
Printer<std::string> stdStringPrinter;
stdStringPrinter.print("C++ is powerful."); // std::string 也可以被通用模板打印
std::vector<bool> boolVec = {true, false, true};
Printer<std::vector<bool>> boolVecPrinter;
boolVecPrinter.print(boolVec); // 调用 `std::vector<bool>` 的全特化版本
return 0;
}偏特化(Partial Specialization):当你只为模板的部分类型参数指定了具体类型,或者对类型参数的某种形式(如指针、引用、常量)进行限制时,就是偏特化。
#include <iostream>
// 通用模板定义
template <typename T1, typename T2>
struct PairInfo {
void display() {
std::cout << "Generic PairInfo for (" << typeid(T1).name() << ", " << typeid(T2).name() << ")" << std::endl;
}
};
// 偏特化:当第二个类型参数是 int 时
template <typename T1>
struct PairInfo<T1, int> {
void display() {
std::cout << "Specialized PairInfo: First type is " << typeid(T1).name() << ", Second type is int." << std::endl;
}
};
// 偏特化:当两个类型参数都是指针时
template <typename T1, typename T2>
struct PairInfo<T1*, T2*> {
void display() {
std::cout << "Specialized PairInfo: Both are pointers to (" << typeid(T1).name() << ", " << typeid(T2).name() << ")" << std::endl;
}
};
int main() {
PairInfo<double, char> info1;
info1.display(); // Generic
PairInfo<double, int> info2;
info2.display(); // Specialized for T2=int
PairInfo<char*, int*> info3;
info3.display(); // Specialized for both are pointers
PairInfo<int, int> info4; // 既匹配 T2=int 的偏特化,也匹配 T1*, T2* 的偏特化(如果 T1* 是 int*)
// 但这里 T1是int,T2是int,所以优先匹配 T2=int 的偏特化
info4.display();
return 0;
}特化发挥关键作用的场景:
bool
std::vector<bool>
以上就是C++如何使用类模板实现通用类的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号