当Qt Creator 11遇上Copilot:我的AI副驾驶如何帮我重构一段老旧C++代码

作为一名长期与Qt打交道的开发者,我最近接手了一个令人头疼的任务——重构一个五年前遗留的Qt项目模块。这段代码不仅充斥着C风格指针操作和冗余的类继承,还夹杂着大量未封装的全局变量。正当我对着屏幕发愁时,GitHub Copilot的插件图标在Qt Creator 11的侧边栏闪动,仿佛在说:"需要帮忙吗?"

1. 从混乱到秩序:AI辅助的代码重构实战

我选取了项目中一个典型的"问题儿童"——一个负责数据解析的DataProcessor类。这个300行的类同时承担了数据读取、格式转换和异常处理三种职责,还混用了new/deleteQSharedPointer两种内存管理方式。

重构第一步:职责拆分 在类声明上方输入注释:

// TODO: Refactor into three specialized classes:
// 1. DataReader - handles file I/O
// 2. DataConverter - manages format conversion  
// 3. DataValidator - implements sanity checks

Copilot立即给出了符合SOLID原则的类结构建议:

class DataReader {
    Q_OBJECT
public:
    explicit DataReader(QObject *parent = nullptr);
    QByteArray readRawData(const QString &filePath);
    // ...
};

class DataConverter {
public:
    QVector<double> convertToDouble(const QByteArray &rawData);
    // ... 
};

内存管理规范化 当我把光标移到一处裸指针使用时,Copilot自动弹出建议:

// 原始代码
void processData() {
    DataCache *cache = new DataCache;
    // ...
    delete cache;
}

// Copilot建议
void processData() {
    auto cache = std::make_unique<DataCache>();
    // 或者使用Qt风格:
    // QScopedPointer<DataCache> cache(new DataCache);
    // ...
} 

2. 现代C++的魔法时刻:AI驱动的语法升级

这个遗留项目还停留在C++11标准,我们决定利用Copilot帮助迁移到C++17特性。

模式匹配改造 当遇到复杂的条件判断时,我输入:

// Convert to modern C++ style
if (auto result = parse(input); result.has_value()) {
    // ...
} else if (auto err = result.error(); err.isCritical()) {
    // ...
}

Copilot不仅完善了代码,还添加了注释说明:

// Using C++17 structured bindings
if (auto [value, error] = parse(input); !error.isEmpty()) {
    qWarning() << "Parse error:" << error;
} else {
    process(*value);
}

Qt特性的智能应用 在重构信号槽连接时,Copilot建议使用Qt5的新语法:

// 替代旧式的 SIGNAL/SLOT 宏
connect(ui->actionSave, &QAction::triggered, 
        this, &MainWindow::saveDocument);

3. 超越补全:Copilot的创造性协作

真正的惊喜发生在处理一个复杂的算法时。原始代码中有个模糊的注释:

// FIXME: This sorting is unstable and slow
void sortEntries(QList<Entry> &entries) {
    // 原始实现...
}

我尝试输入:

// Replace with stable sort using modern STL

Copilot给出了一个带自定义比较器的并行排序方案:

void sortEntries(QList<Entry> &entries) {
    std::stable_sort(
        std::execution::par,
        entries.begin(), 
        entries.end(),
        [](const Entry &a, const Entry &b) {
            return std::tie(a.category, a.timestamp) < 
                   std::tie(b.category, b.timestamp);
        }
    );
}

4. 调试与优化:AI的二次审查

重构完成后,我使用Copilot的"解释代码"功能来验证修改。在任意代码块上右键选择"Explain with Copilot",会得到类似这样的分析:

这段修改后的代码:

  1. 使用std::tie实现多字段比较,避免单独比较可能导致的逻辑错误
  2. std::execution::par启用并行排序,适合大数据集
  3. 保持排序稳定性,确保相同键值的元素保持原始顺序 潜在改进:可添加noexcept说明符,因为比较操作不会抛出异常

性能优化建议 Copilot还能识别潜在的优化点。例如对这段代码:

QString fullPath = dir.path() + "/" + baseName + ".log";

它建议:

// 使用QDir::filePath避免手动拼接路径
QString fullPath = dir.filePath(baseName + ".log"); 
// 或者C++17的path连接
using std::filesystem::path;
path fullPath = path(dir.path().toStdString()) / (baseName + ".log");

5. 经验总结:与AI结对编程的最佳实践

经过两周的密集重构,我总结出这些实用技巧:

有效提示的黄金法则

  • 在注释中明确表达意图而非实现细节
  • 使用TODO/FIXME标记引导Copilot关注点
  • 分步骤请求改进(先结构后实现)

Qt Creator特定技巧

# 设置Copilot专用快捷键(Qt Creator配置示例)
[Shortcuts]
Copilot.NextSuggestion=Alt+]
Copilot.PreviousSuggestion=Alt+[

常见问题应对 当Copilot给出不合适建议时:

  1. Esc清除当前建议
  2. 添加更多上下文注释
  3. 先手动写出函数签名
  4. 使用// Try another approach等明确指令

这个老项目最终减少了38%的代码量,性能提升了2-3倍,而Copilot在这个过程中就像个不知疲倦的协作者,既能在微观层面建议语法改进,也能在架构层面提供设计思路。不过最宝贵的经验是:AI不是替代者,而是放大器——它放大了我的重构效率,但所有关键决策仍需开发者把控。

更多推荐