news 2026/9/16 12:11:07

用C++与QT构建学生选课管理系统:从数据库设计到界面实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用C++与QT构建学生选课管理系统:从数据库设计到界面实战

简介:这是一套基于C++与QT开发的学生选课管理系统,面向计算机相关专业、需要完成毕业设计、期末大作业或课程设计的高校学生,也适合刚接触Qt开发的初学者参考。资源包内含完整可运行的源码、数据库脚本和论文资料,功能覆盖学生信息维护、选课管理、课程表与查询等核心模块,界面美观,操作流程简洁。压缩包共137个文件,整体约58MB,其中h头文件与cpp源文件构成了代码主体,ui文件可直接用Qt Designer打开调整界面,sql文件用于初始化选课相关的数据表,另附pdf论文、mwb数据库模型及png/jpg界面截图,便于快速理解项目结构与部署方式。目前已有192人浏览学习。项目代码注释详细,新手也能看懂,下载后简单部署即可运行;既可直接作为毕业设计或期末大作业使用,也能从中学习Qt窗口设计、信号槽机制、数据库连接与增删改查等核心业务逻辑。

1. 学生选课管理系统为什么值得用 C++ 和 QT 重做一遍

学生选课管理系统是数据库课程设计里最常被选中的题目,但绝大多数提交物是 Java Swing 或 Python Tkinter 写的。用 C++ 和 QT 重做一遍,差别不在于“换了个语言”,而在于这套组合逼着你把两件关键事同时想清楚:一是数据库表结构怎么设计才能撑起选课、退课、成绩录入这些事务;二是客户端程序如何用事件驱动的方式把界面和数据库操作缝在一起。QT 自带的 QSqlQuery、QSqlTableModel 和信号槽机制,让“点按钮 → 查数据库 → 刷新表格”这条链路非常自然,编译出来还是独立可执行文件,演示时比解释型脚本更接近真实桌面软件。这篇文章面向正在做课程设计的学生、以及想从控制台 C++ 转向 GUI 开发的从业者。前两章把表结构和界面骨架立住,中间两章解决选课和退课这两个最难缠的业务,最后一章聊论文素材的整理和答辩演示的顺序。照着走一遍,交上去的是一套能跑、能讲、能答上追问的东西。

2. 学生选课管理系统的数据库设计:从 ER 图到 SQLite 表结构

2.1 为什么选 SQLite 而不是 MySQL:课程设计场景的取舍

先说结论:单机演示、无并发、需要随源码分发,SQLite 是最省事的。MySQL 需要单独安装服务、配置账号密码、答辩现场还可能连不上库;SQLite 是一个文件,QT 通过 Qt SQL 模块内置驱动直接读写,程序跑起来库就跟着走,交源码时把 .db 文件一并打包即可。如果课程设计要求必须使用 MySQL 或 SQL Server,QT 的 QSqlDatabase 切换驱动只改一行连接字符串,后面所有 QSqlQuery 代码完全不用动。

这个取舍也决定了你论文里“数据库选型”一章怎么写:不要写“SQLite 比 MySQL 好”,而是写“本系统面向单机教务管理场景,数据量级在万条以内,SQLite 的零配置特性降低了部署成本,同时通过外键约束和事务保证数据一致性”。这句话在答辩时站得住。

2.2 四张核心表:学生、课程、选课记录、管理员

学生选课管理系统的数据模型围绕两个实体和两个关系展开。学生(student)和课程(course)是实体,选课记录(enrollment)是学生与课程的多对多关系,管理员(admin)负责登录与课程维护。字段设计要克制:学生表只需要学号、姓名、专业、班级;课程表需要课程号、课程名、学分、上课时间、容量、已选人数。上课时间用字符串存储,比如“周一 3-4 节”,冲突检测时在应用层解析,而不是拆成周几和第几节,对小课设来说这一列字符串足够,还能省掉一张时间维度表。

选课表是核心,它的设计直接决定业务逻辑好不好写。主键用自增 ID,同时对学生 ID 和课程 ID 建立联合唯一索引,保证同一学生不能重复选同一门课;外键级联删除,学生退学或课程下架时选课记录自动清理;再加一个选课时间字段,既能按时间排序,也能在论文里写“支持查询选课历史”。容量和已选人数放课程表里,选课事务里用“已选人数 < 容量”做条件更新,这是后面第四章事务控制的地基。

2.2.1 SQLite 建表语句
CREATE TABLE student ( id INTEGER PRIMARY KEY AUTOINCREMENT, student_no TEXT NOT NULL UNIQUE, name TEXT NOT NULL, major TEXT DEFAULT '', class_name TEXT DEFAULT '' ); CREATE TABLE course ( id INTEGER PRIMARY KEY AUTOINCREMENT, course_no TEXT NOT NULL UNIQUE, course_name TEXT NOT NULL, credit REAL DEFAULT 2.0, schedule TEXT DEFAULT '', capacity INTEGER DEFAULT 60, selected INTEGER DEFAULT 0, CHECK (selected >= 0 AND selected <= capacity) ); CREATE TABLE enrollment ( id INTEGER PRIMARY KEY AUTOINCREMENT, student_id INTEGER NOT NULL, course_id INTEGER NOT NULL, create_time TEXT DEFAULT (datetime('now', 'localtime')), UNIQUE (student_id, course_id), FOREIGN KEY (student_id) REFERENCES student(id) ON DELETE CASCADE, FOREIGN KEY (course_id) REFERENCES course(id) ON DELETE CASCADE ); CREATE TABLE admin ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, password TEXT NOT NULL );

这段建表脚本把约束都写在数据库层,而不是依赖应用程序自觉。UNIQUE 约束挡住重复选课,CHECK 约束保证已选人数不会超过容量,外键级联删除省去在 C++ 代码里手动清理关联记录的麻烦。注意 SQLite 默认不开启外键约束,需要在连接建立后执行一次PRAGMA foreign_keys = ON;,否则 ON DELETE CASCADE 不会生效,这是新手最容易踩的坑。

2.3 QT 连接 SQLite 的固定写法

在 QT 里接入数据库,先要在 .pro 文件里加一行QT += sql,然后通过 QSqlDatabase 建立连接。每个连接需要指定连接名,默认连接名是 QSqlDatabase::defaultConnection,单数据库场景下直接用默认连接即可。

#include <QSqlDatabase> #include <QSqlQuery> #include <QSqlError> #include <QDebug> bool initDatabase(const QString& dbPath) { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName(dbPath); if (!db.open()) { qWarning() << "open database failed:" << db.lastError().text(); return false; } QSqlQuery query(db); query.exec("PRAGMA foreign_keys = ON;"); return true; }

QSqlDatabase::addDatabase 的第一个参数是驱动名,QSQLITE 对应 SQLite,QMYSQL 对应 MySQL,驱动名由 QT 安装时的插件决定。setDatabaseName 对 SQLite 来说是数据库文件的路径,传相对路径则相对于程序的工作目录;建议在 main.cpp 里用 QCoreApplication::applicationDirPath() 拼接绝对路径,避免双击启动时工作目录不在源码目录导致找不到库文件。db.open() 失败时先看输出的错误文本,最常见的两类是路径不存在和驱动插件缺失,后者需要确认 QT 安装目录下 plugins/sqldrivers 里有 qsqlite.dll 或 libqsqlite.so。

数据库这层立住之后,下面进界面层。很多人拿到类似的学生选课管理系统源码包习惯先跑起来看界面,但我建议反过来:先把表结构建好,再用 QT 对着表写界面,所有操作都围绕数据模型展开,代码结构会清晰得多。

2.4 这个阶段需要检查的 3 个点

表结构建好后,先别急着写 QT 代码,用命令行工具验证三件事。第一,外键是否真的生效:手动往 enrollment 插入一条不存在的 student_id,应该报 FOREIGN KEY constraint failed。第二,联合唯一约束是否生效:对同一 student_id 和 course_id 连续插两次,第二次应该报 UNIQUE constraint failed。第三,PRAGMA 是否持久:重新打开数据库连接后,执行PRAGMA foreign_keys;应返回 1。这三条验证结果写进论文的“数据库测试”一节,比空写“经过测试系统运行正常”有说服力得多。

提示:如果环境里没有 SQLite 命令行工具,QT Creator 自带的 Database 面板可以直接打开 .db 文件执行 SQL,这在调试阶段比反复重启程序高效。

3. 用 QT Widgets 搭建选课管理系统的界面骨架

3.1 四种界面组件的选型:QWizard、QTabWidget 还是 QStackedWidget

学生选课管理系统的界面从流程上分四块:登录、课程浏览与选课、我的课表、管理端维护。到底用哪种容器组织这些页面,直接影响开发量和演示效果。QTabWidget 把功能平铺成标签页,适合管理端,管理员在“课程管理”“学生管理”之间来回切换很顺手;QStackedWidget 一次只显示一页,配合左侧导航栏更像完整桌面应用,适合学生端;QWizard 是多步向导,适合做成“入学选课”这种分步流程,但日常使用会显得笨重。我一般会做两套界面:学生端用 QStackedWidget 加左侧 QListWidget 导航,管理端直接上 QTabWidget,代码量差不多,答辩时界面层次感明显强于一页堆满按钮。

登录页单独用一个 QDialog,对话框的 exec() 是模态的,登录失败时弹 QMessageBox::warning 并让对话框保持打开,成功后 accept() 关闭并进入主窗口。这个交互模式在课设答辩里是默认加分项:评审老师会直接关掉主窗口然后重新运行,一个带模态校验的登录框能挡住“绕过登录直接进主界面”的质疑。

3.1.1 主窗口框架的最小代码
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) { auto* stack = new QStackedWidget(this); auto* nav = new QListWidget(this); nav->addItem("全部课程"); nav->addItem("我的选课"); nav->addItem("个人信息"); auto* listPage = new QWidget(this); auto* myPage = new MyCoursePage(this); auto* infoPage = new QWidget(this); stack->addWidget(listPage); // index 0 stack->addWidget(myPage); // index 1 stack->addWidget(infoPage); // index 2 auto* splitter = new QSplitter(Qt::Horizontal, this); splitter->addWidget(nav); splitter->addWidget(stack); setCentralWidget(splitter); connect(nav, &QListWidget::currentRowChanged, stack, &QStackedWidget::setCurrentIndex); }

这段代码里最值得说明的是 connect 那一行:导航列表的 currentRowChanged 信号直接连到 QStackedWidget 的 setCurrentIndex 槽,索引一一对应,不需要写 if 分支。界面切换用信号槽解耦后,后续加新页面只需 addWidget 并在导航里加一项,改动局限在两行以内。QSplitter 允许用户拖动分隔条,演示时故意拖动一下,能让评审觉得这个是打磨过的应用而不是作业拼凑。

3.2 数据展示:QTableView + QSqlQueryModel 比手动拼 widget 高效

课程列表是系统里数据量最大的界面,几百门课如果用 QVBoxLayout 逐个 new QLabel 和 QPushButton,内存和布局开销都很大,刷新还要手动清理旧控件。正确的做法是模型/视图架构:QTableView 做视图,QSqlQueryModel 或 QSqlTableModel 做数据源,QT 负责把模型的每一行画出来。

auto* model = new QSqlQueryModel(tableView); model->setQuery( "SELECT course_no AS 课程号, course_name AS 课程名, " "credit AS 学分, schedule AS 上课时间, " "selected || '/' || capacity AS 选课人数 " "FROM course ORDER BY course_no", db); model->setHeaderData(0, Qt::Horizontal, "课程号"); model->setHeaderData(1, Qt::Horizontal, "课程名"); tableView->setModel(model); tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

setQuery 不只是执行 SQL,它会根据查询结果自动决定表格列数;SELECT 里用 AS 起中文别名,列标题就不用再手动设置。selected || '/' || capacity 是利用 SQLite 的字符串拼接,直接显示“45/60”这种格式,QT 端拿到的是一个字符串列,省去在 C++ 里 format 的步骤。模型每次刷新只需要再调用一次 setQuery,表格自动更新,不用碰任何单元格控件。注意 QSqlQueryModel 是只读的,学生端查看课程用它正合适;管理端要编辑课程信息,得换 QSqlTableModel 并设置 editStrategy,接 QTableView 的代码完全一致。

3.3 让界面响应中文:源码编码与字体一次配好

用 QT 写中文界面,绝大多数“乱码”问题出在源码文件编码,而不是 QT 本身。MSVC 编译器默认按本地代码页读源文件,如果 .cpp 存成 UTF-8 而编译器按 GBK 解析,中文字符串就会变乱码。常见做法是在 .pro 文件里加msvc: QMAKE_CXXFLAGS += /utf-8,同时用 QStringLiteral 包裹中文字符串,两个措施配合使用。以下是我常用的写法:

QString courseName = QStringLiteral("数据结构");

保存源码时统一 UTF-8 编码,配合 /utf-8 编译选项后,中文字符串不会在任何编译器上出问题。字体方面,界面全局设置一次QApplication::setFont(QFont("Microsoft YaHei", 10))即可,Linux 下换成 "WenQuanYi Micro Hei"。数据库本身存中文不需要额外设置,SQLite 以 UTF-8 存储,QT 驱动负责转码,只要文件编码和编译器编码统一,全链路不会出现中文变问号的情况。

3.4 QT 绘图:用自定义委托画容量条

选课页面如果每门课只显示“45/60”的数字,视觉信息量不足。用 QPainter 在委托里画一个容量进度条,能明显提升演示效果,这也是 QT 绘图在实际业务里最自然的落点。QStyledItemDelegate 重写 paint(),根据“已选/容量”比例填充矩形,选满的课程用红色,未满用绿色。

class CapacityDelegate : public QStyledItemDelegate { public: void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override { QString text = index.data().toString(); int slash = text.indexOf('/'); int selected = text.left(slash).trimmed().toInt(); int capacity = text.mid(slash + 1).trimmed().toInt(); double ratio = capacity > 0 ? double(selected) / capacity : 0.0; painter->save(); if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); } QColor barColor = (selected >= capacity) ? QColor(220, 80, 80) : QColor(80, 180, 120); painter->fillRect(option.rect.adjusted(4, 8, -4, -8), QColor(230, 230, 230)); int barWidth = qRound((option.rect.width() - 8) * ratio); painter->fillRect( option.rect.adjusted(4, 8, -(option.rect.width() - 8 - barWidth), -8), barColor); painter->drawText(option.rect, Qt::AlignCenter, text); painter->restore(); } };

把这个委托 setItemDelegateForColumn 到课程表格的第三列后,容量信息一目了然。注意 paint() 里不要 new 对象,painter->save/restore 保护状态,否则滚动时会出现绘制残影。委托的实现在论文里可以单独开一小节“基于 QStyledItemDelegate 的自定义数据呈现”,有代码有截图,属于加分内容。

4. 选课与退课核心流程:QSqlQuery 增删改查与事务控制

4.1 选课按钮背后的四步逻辑

用户点击“选课”按钮后,程序要按顺序完成四件事:选课记录是否存在、课程是否已满、写入 enrollment 表、课程表已选人数加一。前两步是校验,后两步是写入。校验放客户端,写入必须放事务里,否则并发环境下会出现超选。

先看最简单直接的实现——用 QSqlQuery 逐条执行:

bool enrollStudent(QSqlDatabase& db, int studentId, int courseId) { QSqlQuery q(db); q.prepare("SELECT COUNT(*) FROM enrollment " "WHERE student_id = ? AND course_id = ?"); q.addBindValue(studentId); q.addBindValue(courseId); if (!q.exec() || !q.next()) return false; if (q.value(0).toInt() > 0) { QMessageBox::warning(nullptr, "提示", "请勿重复选课"); return false; } q.prepare("SELECT selected, capacity FROM course WHERE id = ?"); q.addBindValue(courseId); if (!q.exec() || !q.next()) return false; if (q.value(0).toInt() >= q.value(1).toInt()) { QMessageBox::warning(nullptr, "提示", "该课程已满"); return false; } if (!db.transaction()) { qWarning() << "transaction start failed"; return false; } q.prepare("INSERT INTO enrollment (student_id, course_id) " "VALUES (?, ?)"); q.addBindValue(studentId); q.addBindValue(courseId); bool okInsert = q.exec(); q.prepare("UPDATE course SET selected = selected + 1 WHERE id = ?"); q.addBindValue(courseId); bool okUpdate = q.exec(); if (okInsert && okUpdate) { db.commit(); return true; } db.rollback(); return false; }

这段代码把两个写操作放进一个事务:只有选课记录插入成功且人数加一成功,才 commit;任何一个失败就 rollback,避免出现“课表里有这门课但人数没加”或反过来的一致性问题。prepare + addBindValue 是必须的写法,直接用 QString 拼接 SQL 一旦课名或备注里出现单引号,轻则语法错误,重则留下 SQL 注入面,课设虽小,但这个习惯要养对。注意 SELECT COUNT(*) 校验放在事务外也可以,因为在单机场景下同一时刻只有一个客户端在写;如果换成 MySQL 且启用多客户端并发,这套校验必须放进事务里配合 SELECT ... FOR UPDATE 使用。

4.2 退课为什么比选课更容易出错

退课的 SQL 更简单,麻烦在业务规则:已经录入成绩的选课记录能不能退?课程被删除后选课记录还存在吗?绝大多数课程设计要求“未录入成绩可退课,已录入不可退”,所以我建议 enrollment 表加一列 score,默认 NULL,期末录入成绩后写入:

bool dropCourse(QSqlDatabase& db, int studentId, int courseId) { QSqlQuery q(db); q.prepare("SELECT score FROM enrollment " "WHERE student_id = ? AND course_id = ?"); q.addBindValue(studentId); q.addBindValue(courseId); if (!q.exec() || !q.next()) return false; if (q.value(0).isValid()) { QMessageBox::warning(nullptr, "提示", "该课程已录入成绩,无法退课"); return false; } db.transaction(); q.prepare("DELETE FROM enrollment WHERE student_id = ? AND course_id = ?"); q.addBindValue(studentId); q.addBindValue(courseId); bool okDelete = q.exec(); q.prepare("UPDATE course SET selected = selected - 1 WHERE id = ?"); q.addBindValue(courseId); bool okUpdate = q.exec(); if (okDelete && okUpdate) { db.commit(); return true; } db.rollback(); return false; }

score 字段的 NULL 判断是关键:q.value(0).isValid() 为 false 表示该列值为 NULL,即还未录入成绩;一旦录了成绩,即使 0 分也是浮点数而非 NULL,不会误判。查询时如果是 SELECT * 而不是显式列出字段,后面的列顺序一变,value(0) 的含义就全变了,所以生产代码一定要显式写列名。

4.3 QSqlQuery 增删改查的常见错误与排查顺序

这一节把 QSqlQuery 使用中最常踩的坑按出现频率排下来,按这个顺序排查比逐个断点调试快得多。

现象最常见原因排查方法
程序启动时报 driver not loaded缺少 QSQLITE 插件或部署时未带 sqldrivers 目录打印 QSqlDatabase::drivers() 确认包含 QSQLITE;检查可执行文件旁 plugins/sqldrivers 是否存在
exec() 返回 false,lastError 为空查询对象未指定 db,用了另一个连接的默认库创建 QSqlQuery 时传入 db:QSqlQuery q(db);
中文写入数据库后变成 ?源码编码或编译器编码不一致.pro 加 /utf-8,源文件存 UTF-8,参考 3.3 节
事务中某条 execute 失败但数据仍写进去忘记 rollback,或 QSqlQuery 复用了未 finish 的查询每次 exec 后检查返回值,失败立即 rollback
删除课程后选课表还有残留SQLite 外键未开启连接后执行 PRAGMA foreign_keys = ON
表格刷新后原来的排序丢失QSqlQueryModel 不持久化排序状态记录排序列和方向,刷新后重放 ORDER BY

QSqlError 的 text() 对 SQLite 来说通常能直接读,比如 UNIQUE constraint failed: enrollment.student_id, enrollment.course_id,一眼就能看出是重复选课。遇到 SQL 语法错误先去命令行把同一条 SQL 跑一遍,能跑通再回来查 QT 端的 prepare 和绑定参数是否一一对应。

4.4 并发与重复提交:按钮防抖和唯一索引兜底

数据库层之外,还有两个保护要补在 UI 上。第一,选课按钮点击后立即 setEnabled(false),等事务 commit 后再恢复,防止快速双击提交两次。第二就是数据库层那个 UNIQUE 约束,即使按钮防抖失效,第二次 INSERT 也会被数据库拒绝;程序捕获 QSqlError,判断错误文本里是否含 UNIQUE,给出友好提示而不是把原始错误弹给用户。一前一后两道防线,足以应付演示现场的所有误操作。

5. 论文资料整理、QT 打包发布与答辩演示技巧

5.1 从源码生成论文核心素材的流程

课设论文一般分九节:摘要、需求分析、概要设计、详细设计、数据库设计、界面实现、测试、总结、参考文献。其中详细设计和测试两节最容易凑字数也最容易被忽视。建议用 Doxygen 跑一遍核心类,把类图和成员列表贴进论文,但不要贴满屏代码,挑三段:信号槽连接、事务选课、自定义委托绘制,每段配 100 字左右的分析就够。

需求分析别写“本系统满足选课需求”这种空话,用用例表列六个用例:学生登录、浏览课程、选课、退课、查看已选课程、管理员维护课程。每个用例写前置条件、正常流程、异常流程三行。这部分内容从第四章节的代码里直接提炼即可,不需要虚构,评审老师按表核对代码,对得上就是有效内容。

测试部分最有价值的是异常路径测试记录。我通常会建一个测试记录表,列出“重复选课”“选已满课程”“退已评分课程”“删除有选课学生的课程”四条测试项,每条写明预期行为和实际表现。这四条数据在第四章代码里都有对应处理,跑一遍截个图,测试章节立刻充实。

5.2 windeployqt 打包成一个可运行的文件夹

课程设计交源码,但答辩现场是拿发布版本演示的。QT 程序在装了 QT 的机器上能跑,换到评委机器就报缺少 Qt5Widgets.dll,需要用官方部署工具把运行依赖收齐。Windows 下的固定流程:用 Release 模式编译,打开 QT 对应版本位数命令行,cd 到 exe 所在目录,执行:

windeployqt StudentCourseSystem.exe

该命令会把 Qt5Core.dll、Qt5Gui.dll、Qt5Widgets.dll、Qt5Sql.dll 和 platforms/sqldrivers 等插件目录一并复制到 exe 旁。打包完成后把整个文件夹压缩成 zip,交源码时附上 db 文件和初始化 SQL 脚本。执行 windeployqt 前先确认 PATH 里能访问到 qmake,否则工具找不到 QT 安装目录,此时到 QT 安装目录的 bin 下执行即可。

5.3 一个让答辩更稳的演示顺序

如果把所有功能按正常流程走一遍,容易漏掉精彩的部分。我推荐的演示路径是先跑异常后跑正常:第一步登录,展示密码校验;第二步输入一个不存在的学号,展示“查无此人”提示;第三步选一个已满课程,展示容量条变红且拒绝选课;第四步正常选课,展示容量条数字更新;第五步打开“我的选课”,展示课表与课程列表联动刷新。异常在前,正常在后,能证明你已经想过边界情况。

5.4 用 sqlite 内存模式做自动化冒烟测试

最后一个技巧:系统上线前写一个不依赖 GUI 的冒烟测试入口,用:memory:作为数据库名创建内存库,加载建表脚本后调用核心业务函数,全程不需要 QT 事件循环,适合在 CI 或课程设计测试报告里附加输出。

void smokeTest() { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "testConn"); db.setDatabaseName(":memory:"); if (!db.open()) return; QSqlQuery q(db); q.exec("CREATE TABLE course (id INTEGER PRIMARY KEY, " "course_name TEXT, capacity INTEGER, selected INTEGER DEFAULT 0)"); q.exec("INSERT INTO course VALUES (1, '数据结构', 2, 0)"); qDebug() << "enroll #1:" << enrollStudent(db, 1001, 1); qDebug() << "enroll #2:" << enrollStudent(db, 1002, 1); qDebug() << "enroll #3:" << enrollStudent(db, 1003, 1); }

:memory:数据库在连接关闭时自动销毁,测试不会污染真实数据文件。第三条选课因为容量为 2 应该返回 false,输出里第三条 false 就说明选课上限规则生效。这个冒烟测试放 main.cpp 里用宏开关控制,开发阶段打开,演示版关闭,既不影响发布包,又能在论文测试章节里贴一张真实输出,比“系统经过测试”六个字可信得多。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 12:10:15

LoRA微调LLaMA-2实战:从CUDA注入到Tokenizer对齐的端到端闭环

简介&#xff1a;本资源是一套面向AI开发者与大模型初学者的LLaMA快速微调实战项目&#xff0c;聚焦自然语言处理任务中的模型适配与工程落地&#xff0c;解决预训练大模型如何高效适配垂直场景的核心问题。压缩包共340个文件&#xff0c;涵盖159个Python训练/数据处理脚本、40…

作者头像 李华
网站建设 2026/9/16 12:09:58

Claude Code 报错无法连接 Anthropic?TaoToken 这样改 Base URL

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/16 12:09:33

飞秒激光与金属相互作用:双温模型与MATLAB数值模拟

1. 飞秒激光与金属相互作用的基础物理模型飞秒激光与金属相互作用是一个典型的非平衡态热力学过程。当超短脉冲激光&#xff08;通常脉宽在10-100飞秒量级&#xff09;照射金属表面时&#xff0c;光子能量首先被电子吸收&#xff0c;由于电子-声子耦合时间尺度&#xff08;约1皮…

作者头像 李华
网站建设 2026/9/16 12:09:08

Pentagi:基于Neo4j与轻量AI Agent的攻击链认知建模系统

1. 项目概述&#xff1a;Pentagi 是什么&#xff1f;它解决的不是“渗透测试自动化”&#xff0c;而是“攻击链认知建模”的根本问题Pentagi 这个名字乍看像拼写错误&#xff0c;实则暗藏玄机——它由Penetration Tagi&#xff08;源自拉丁语tactus&#xff0c;意为“触达”“连…

作者头像 李华
网站建设 2026/9/16 12:08:50

高温结构强度与蠕变寿命仿真技术解析

1. 高温结构强度与蠕变寿命仿真概述在航空航天、能源化工等工业领域&#xff0c;高温环境下的结构强度与蠕变寿命评估一直是工程设计中的关键难题。当金属材料长期暴露在高温环境中&#xff0c;即使承受的应力远低于其屈服强度&#xff0c;也会因蠕变效应逐渐产生塑性变形&…

作者头像 李华