《C++ 小程序编写系列》(第六部)

前言:从多态到泛型 ------C++ 编程的进阶之路

在第五部中,我们通过继承与多态实现了管理员、读者等多角色的权限分离,以及图书、期刊等不同资源的统一管理。但系统仍存在局限性:所有数据类型(图书 ID、读者编号、借阅日期等)均为固定类型(如int、string),若需支持自定义类型(如 ISBN 结构体、自定义日期类)或扩展数据格式(如批量导入 Excel 数据),则需大量修改原有代码。

本系列第六部将通过模板编程STL(标准模板库) 解决这一问题,打造一个 "一次编写、多类型适配" 的泛型化图书管理系统。核心目标包括:

  1. 用类模板实现通用数据容器,支持图书、读者、借阅记录等多类型数据的统一存储;
  1. 用函数模板封装通用操作(排序、查找、过滤),适配不同数据类型的业务逻辑;
  1. 结合 STL 容器(vector、map、set)与算法(sort、find_if)优化数据管理效率;
  1. 兼容第五部的多角色权限系统,实现泛型与多态的协同工作。

第一章:泛型编程基础 ------ 模板的核心语法

1.1 类模板:通用数据载体的设计

类模板允许我们定义 "数据类型参数化" 的类,例如通用的 "数据存储容器",可适配图书、读者、借阅记录等任意类型:

复制代码

// 通用数据容器模板(替代第五部的固定类型数组)

template T>

class DataContainer {

private:

vector // 借助STL vector实现动态存储

public:

// 添加数据(自动适配T类型)

void addData(const T& data) {

dataList.push_back(data);

}

// 查找数据(接收自定义匹配规则)

vector<T> findData(function(const T&)> matchRule) {

vector> result;

for (const auto& data : dataList) {

if (matchRule(data)) {

result.push_back(data);

}

}

return result;

}

// 排序数据(接收自定义比较规则)

void sortData(function T&, const T&)> compareRule) {

sort(dataList.begin(), dataList.end(), compareRule);

}

// 其他通用方法:删除、遍历、清空...

};

关键优势:无需为图书(Book)、读者(Reader)分别定义容器类,一套代码适配所有类型,且借助vector自动处理内存分配与扩容。

1.2 函数模板:通用业务逻辑的封装

函数模板用于封装与数据类型无关的逻辑,例如数据校验、格式转换等。以 "借阅记录有效性检查" 为例:

复制代码

// 通用数据有效性校验模板

template >

bool isValidData(const T& data) {

// 利用C++11的type_traits实现类型差异化校验

if constexpr (is_same_v {

// 借阅记录:借阅日期 归还日期

return data.borrowDate Date;

} else if constexpr (is_same_v

// 图书:ID非空、库存量 >= 0

return !data.bookId.empty() && data.stock >= 0;

} else if constexpr (is_same_v<T, Reader>) {

// 读者:编号非空、年龄 >= 0

return !data.readerId.empty() && data.age >= 0;

} else {

// 默认:自定义类型需自行扩展校验逻辑

return true;

}

}

核心特性:通过constexpr与type_traits实现编译期类型判断,避免运行时开销,同时支持类型的灵活扩展。


第二章:泛型化图书管理系统的架构升级

2.1 系统核心组件重构(兼容第五部)

基于模板与 STL,重构第五部的核心类,保持多角色权限体系不变,仅优化数据存储与操作逻辑:

|--------|-------------------------|-----------------------------------------------|
| 组件 | 第五部实现(固定类型) | 第六部实现(泛型化) |
| 图书存储 | Book books[100](静态数组) | DataContainer bookContainer |
| 读者存储 | Reader readers[100] | DataContainer |
| 借阅记录存储 | 独立数组 | DataContainer<BorrowRecord> borrowContainer |
| 查找逻辑 | 硬编码条件判断 | 函数对象(function)传入匹配规则 |
| 排序逻辑 | 针对特定类型的排序函数 | 通用sortData+ 自定义比较规则 |

2.2 关键业务场景实现
场景 1:多条件查找图书(支持不同查询维度)
复制代码

// 示例:查找"计算机类"且"库存量>0"的图书

auto computerBooks = bookContainer.findData([](const Book& book) {

return book.category == "计算机" && book.stock > 0;

});

// 示例:查找"2024年之后出版"的图书

auto newBooks = bookContainer.findData([](const Book& book) {

return book.publishYear >= 2024;

});

优势:无需修改容器类代码,仅通过 lambda 表达式传入查询条件,支持无限扩展查询维度。

场景 2:自定义排序(适配不同业务需求)
复制代码

// 示例1:按图书库存量降序排序

bookContainer.sortData([](const Book& a, const Book& b) {

return a.stock > b.stock;

});

// 示例2:按读者年龄升序排序

readerContainer.sortData([](const Reader& a, const Reader& b) {

return a.age });

原理:借助 STL 的sort算法,通过函数对象传递比较规则,实现对任意类型数据的排序。

场景 3:多类型数据批量导入
复制代码

// 通用数据导入模板(支持从文件导入任意类型)

template >

bool importDataFromFile(const string& filePath, DataContainer {

ifstream file(filePath);

if (!file.is_open()) return false;

T data;

while (file >> data) { // 需为自定义类型重载>>运算符

if (isValidData(data)) { // 调用通用校验模板

container.addData(data);

}

}

file.close();

return true;

}

// 调用示例:导入图书数据和读者数据

importDataFromFile<Book>("books.txt", bookContainer);

importDataFromFile.txt", readerContainer);

扩展性:只需为新数据类型(如Journal期刊)重载输入运算符和校验逻辑,即可直接复用导入功能。


第三章:泛型与多态的协同工作

3.1 模板类中使用多态(角色权限控制)

第五部中通过多态实现了管理员、读者的权限分离,第六部中可在泛型容器中直接存储基类指针,保留多态特性:

复制代码

// 存储角色基类指针的泛型容器

DataContainer*> roleContainer;

// 添加不同角色(多态特性保留)

roleContainer.addData(new Admin("admin001", "123456"));

roleContainer.addData(new ReaderUser("reader001", "654321", 25));

// 调用多态方法(无需关心具体角色类型)

auto allRoles = roleContainer.findData([](Role* role) {

return true; // 查找所有角色

});

for (auto role : allRoles) {

role->showMenu(); // 动态绑定:管理员显示管理员菜单,读者显示读者菜单

}

核心要点:模板容器支持存储指针类型,结合多态可实现 "通用存储 + 差异化行为",兼顾灵活性与扩展性。

3.2 模板特化:处理特殊类型的差异化需求

当通用模板无法满足特定类型的需求时,可使用模板特化。例如,为BorrowRecord(借阅记录)特化findData方法,支持按日期范围查询:

复制代码

// 为BorrowRecord类型特化DataContainer的findData方法

template <>

vectorRecord> DataContainerRecord>::findData(function(const BorrowRecord&)> matchRule) {

// 扩展:先按借阅日期排序,再执行匹配(优化查询效率)

sortData([](const BorrowRecord& a, const BorrowRecord& b) {

return a.borrowDate ;

});

// 调用通用逻辑

return DataContainerRecord>::findData(matchRule);

}

作用:在保持通用逻辑的同时,为特殊类型提供定制化优化,避免 "一刀切" 的设计缺陷。


第四章:系统测试与性能优化

4.1 功能测试(验证泛型兼容性)
  1. 多类型支持测试:分别添加Book、Reader、BorrowRecord数据,验证存储、查找、排序功能正常;
  1. 扩展类型测试:新增Journal(期刊)类,无需修改容器代码,直接复用DataContainer与isValidData模板;
  1. 多态协同测试:通过Role*指针调用不同角色的方法,验证多态行为正常。
4.2 性能优化(STL 的高效使用)
  1. 容器选择:用map存储图书 ID 与图书对象的映射,实现 O (1) 时间复杂度的 ID 查询:
复制代码

mapMap; // key: 图书ID,value: 图书对象

  1. 算法优化:使用find_if替代手动遍历,结合lambda表达式简化代码:
复制代码

// 查找ID为"book001"的图书(STL算法版)

auto it = find_if(bookList.begin(), bookList.end(), [](const Book& book) {

return book.bookId == "book001";

});

  1. 内存管理:使用智能指针(shared_ptr)替代裸指针,避免内存泄漏:
复制代码

DataContainer<shared_ptrContainer;

roleContainer.addData(make_shared>("admin001", "123456"));


总结与后续展望

本章节通过模板与 STL 实现了图书管理系统的泛型化升级,核心收获包括:

  • 掌握类模板与函数模板的定义与使用,实现代码复用;
  • 学会结合 STL 容器与算法优化数据管理,提升开发效率;
  • 理解泛型与多态的协同机制,打造灵活可扩展的系统架构。

后续系列预告 :第七部将聚焦C++ 11 + 新特性实战,包括并发编程(thread、mutex)、智能指针深度应用、lambda 表达式高级用法等,进一步提升系统的性能与稳定性。

相关推荐
23124_802 小时前
HTTPS中间人攻击
网络·网络协议·https
それども2 小时前
怎么理解 HttpServletRequest @Autowired注入
java
牧小七2 小时前
java JShell 怎么使用
java
小毅&Nora2 小时前
【Java线程安全实战】⑭ ForkJoinPool深度剖析:分治算法的“智能厨房“如何让并行计算跑得更快
java·算法·安全
小风呼呼吹儿2 小时前
Flutter 框架跨平台鸿蒙开发 - 倒计时秒表:打造多功能计时工具
网络·flutter·华为·harmonyos
河码匠2 小时前
namespace 网络命名空间、使用网络命名空间实现虚拟路由
linux·网络
开开心心就好2 小时前
打印机驱动搜索下载工具,自动识别手动搜
java·linux·开发语言·网络·stm32·物联网·电脑
yangminlei2 小时前
基于 Java 的消息队列选型年度总结:RabbitMQ、RocketMQ、Kafka 实战对比
java·java-rocketmq·java-rabbitmq
海域云-罗鹏2 小时前
马来西亚工厂与内地数据中心SD-WAN组网全指南
服务器·网络