当前位置: 首页 > news >正文

C++泛型编程2 - 类模板

C++ 类模板全面教程

类模板是C++中强大且灵活的特性,它允许我们创建可适用于多种数据类型的类。下面我将从基础到高级,系统性地介绍类模板。

一、类模板基本概念

1.1 什么是类模板

类模板是一种允许我们使用不同类型创建类的蓝图。就像函数模板可以生成针对不同类型参数的函数一样,类模板可以生成针对不同类型参数的类。

1.2 为什么需要类模板

假设你需要一个可以存储任何类型数据的栈,不使用模板就需要为每种类型分别创建类:

class IntStack { /* 实现int栈 */ };
class DoubleStack { /* 实现double栈 */ };
class StringStack { /* 实现string栈 */ };

使用类模板则可以定义一次,适应多种类型:

template <typename T>
class Stack { /* 通用栈实现 */ };

二、类模板基本语法

2.1 基本定义

template <typename T>    // 或者 template <class T>
class MyClass {// 类成员定义
};

2.2 示例:一个简单的Array类模板

template <typename T>
class Array {
private:T* ptr;int size;public:Array(int s) : size(s), ptr(new T[s]) {}~Array() { delete[] ptr; }T& operator[](int index) {if (index >= size || index < 0) {throw std::out_of_range("Index out of range");}return ptr[index];}int getSize() const { return size; }
};

2.3 使用类模板

Array<int> intArr(10);      // 创建存储int的数组
Array<double> doubleArr(5); // 创建存储double的数组

三、类模板的定义与使用

3.1 多个类型参数

template <typename T, typename U>
class Pair {
public:T first;U second;Pair(const T& f, const U& s) : first(f), second(s) {}
};Pair<int, double> p1(1, 3.14);
Pair<std::string, bool> p2("success", true);

3.2 默认类型参数

template <typename T, typename U = bool>
class Pair {
public:T first;U second;Pair(const T& f, const U& s) : first(f), second(s) {}
};Pair<int, double> p1(1, 3.14);
Pair<std::string> p2("success", true);	// 使用默认类型

3.3 默认非类型参数

template <typename T = int, int size = 10>
class Container {T items[size];// ...
};Container<> defaultContainer;          // 使用默认参数 T=int, size=10
Container<double, 20> customContainer; // 指定参数

3.4 成员函数模板

类内部可以定义成员函数模板:

template <typename T>
class Box {T content;public:template <typename U>void assign(const U& newContent) {content = newContent; // 需要U能隐式转换为T}
};

3.5 成员函数的类外实现

成员函数类外实现,模板声明必须和类模板一致,但无需给出默认参数。以为类名作用域需要指定类型,即必须用模板类型实例化,才能使用。

template <class T1, class T2>
class 类名{T1 函数名(T2 a, T2 b);
}// 注意类名作用域使用模板参数进行实例化。
template <class T1, class T2>
T1 类名<T1, T2>::函数名(T2 a, T2 b){// 函数实现
}

3.6 类模板实例化

与函数模板不同,类模板只能显式实例化,不能隐式实例化。因为函数模板调时可以根据参数自动判断类型,而类模板调用时除了显式指定,没有任何参考依据。

template <class T>
class Complex{T real;T img;
}// 使用类模板创建对象
Complex<int> c;

3.7 类模板作为函数参数

1. 普通函数

类模板在普通函数中使用必须实例化为一个具体的类:

template <class T>
class Complex{T real;T img;
}Complex<double> add(Complex<double> a, Complex<double> b);
2. 函数模板

方法一:常用,用泛型类型实例化类模板作为函数参数类型。

template <class T>
class Complex{T real;T img;
}template <class T>
Complex<T> add(Complex<T> a, Complex<T> b);

方法二:通用所有类,在使用时再指定类。

template <class T>
class Complex{T real;T img;
}template <class T>
T add(T a, T b);

四、类模板特化

4.1 全特化

所有类型参数都必须具体化。

template <>
class Array<bool> {
private:unsigned char* ptr;int size;public:// 特化实现,按位存储bool以节省空间Array(int s) : size(s), ptr(new unsigned char[(s+7)/8]) {}~Array() { delete[] ptr; }// 其他特化实现...
};

4.2 偏特化

只具体化部分类型参数。没有具体化的泛型类型在仍然在<>中。而类定义的实例化中可以使用泛型类型。

template <class T>
class 类名<T, string>{}

五、类模板中的静态成员

类模板中的static成员对于每个模板实例化都是独立的:

template <typename T>
class Counter {
public:static int count;Counter() { ++count; }~Counter() { --count; }
};template <typename T>
int Counter<T>::count = 0;Counter<int> c1, c2;    // Counter<int>::count == 2
Counter<double> c3;     // Counter<double>::count == 1

六、类模板继承

6.1 从类模板继承

template <typename T>
class Base {// ...
};template <typename T>
class Derived : public Base<T> {// ...
};

6.2 继承关系中的名称查找

在模板继承中需要使用this->Base<T>::来访问基类成员:

template <typename T>
class Derived : public Base<T> {
public:void foo() {this->baseMember();  // 使用this->访问基类成员Base<T>::baseMember(); // 或使用完整限定名}
};

七、类模板与友元

7.1 友元函数

template <typename T>
class MyClass {T value;// 声明友元函数friend void printValue(const MyClass<T>& obj) {std::cout << obj.value;}
};MyClass<int> obj;
printValue(obj); // 正确调用

7.2 友元类

template <typename T>
class FriendClass; // 前向声明template <typename T>
class MyClass {
private:T secret;friend class FriendClass<T>; // 声明友元类
};

八、使用技巧与最佳实践

  1. 分离实现与声明:可以将类模板的声明放在头文件,定义放在另一个头文件(如.tpp.ipp),然后在声明文件末尾包含定义文件。

  2. 防止模板膨胀:避免生成过多不必要的模板实例,可通过特化等方式优化。

  3. 明确错误信息:模板错误通常在实例化时才被发现,使用static_assert提供更友好的错误信息:

template <typename T>
class NumericArray {static_assert(std::is_arithmetic<T>::value, "NumericArray requires an arithmetic type");// ...
};

总结

类模板特点

  • 只能显式实例化,不能隐式实例化
  • 可以指定默认类型

类模板是C++泛型编程的核心技术之一,通过类模板我们可以:

  1. 编写与类型无关的通用代码
  2. 减少代码重复,提高复用性
  3. 在编译时完成类型检查,确保类型安全
  4. 通过特化提供特定类型的优化实现

掌握类模板能显著提升你的C++编程能力,特别是在开发和维护大型库时。建议从简单例子开始,逐步尝试更复杂的应用场景。

http://www.lryc.cn/news/576690.html

相关文章:

  • C# 委托(为委托添加方法和从委托移除方法)
  • 13-StringBuilder类的使用
  • Linux内核网络协议栈深度解析:面向连接的INET套接字实现
  • 8. 【Vue实战--孢子记账--Web 版开发】-- 账户账本管理
  • Uni-App 小程序面试题高频问答汇总
  • 【Docker基础】Docker容器管理:docker top及其参数详解
  • Ubuntu 主机通过 `enp4s0` 向开发板共享网络的完整步骤
  • Flutter基础(控制器)
  • 广外计算机网络期末复习
  • 大模型之提示词工程入门——解锁与AI高效沟通的“钥匙”
  • WOE值:风险建模中的“证据权重”量化术——从似然比理论到FICO评分卡实践
  • python学习打卡day57
  • Python基础(吃洋葱小游戏)
  • 如何让ChatGPT模仿人类写作,降低AIGC率?
  • SpringBoot3.x整合Knife4j接口文档
  • cocos creator 3.8 - 精品源码 - 六边形消消乐(六边形叠叠乐、六边形堆叠战士)
  • 阿里 Qwen3 模型更新,吉卜力风格get
  • (五)神经网络
  • 【数据标注师】线标注
  • Linux软连接和硬连接
  • 复杂驱动开发-TLE9471的休眠流程与定时唤醒
  • 断路器、空气开关、漏电保护器
  • 【扩欧应用】同余方程
  • 概述-4-通用语法及分类
  • 领域驱动设计(DDD)【21】之值对象的优势
  • WebRTC(十二):DTLS
  • PowerBI 柱状图显示MoM销量环比示例,以及解决相同列值时设置柱子颜色的问题
  • 【转】PostgreSql的镜像地址
  • 一个简单测试Deepseek吞吐量的脚本,国内环境可跑
  • QTreeWidget 简单使用