|
|
# 代码质量标准知识体系
|
|
|
|
|
|
## 编码规范标准
|
|
|
|
|
|
### Qt Coding Style
|
|
|
```cpp
|
|
|
// 类名使用帕斯卡命名法
|
|
|
class MainWindow : public QMainWindow
|
|
|
{
|
|
|
Q_OBJECT
|
|
|
|
|
|
public:
|
|
|
explicit MainWindow(QWidget *parent = nullptr);
|
|
|
~MainWindow();
|
|
|
|
|
|
private slots:
|
|
|
void onButtonClicked(); // 槽函数使用on前缀
|
|
|
|
|
|
private:
|
|
|
Ui::MainWindow *ui; // 成员变量使用驼峰命名
|
|
|
QTimer *m_timer; // 私有成员使用m_前缀
|
|
|
};
|
|
|
```
|
|
|
|
|
|
### Google C++ Style Guide要点
|
|
|
- **命名约定**:类名PascalCase,函数名camelCase,常量UPPER_CASE
|
|
|
- **文件组织**:头文件包含顺序,前向声明的使用
|
|
|
- **代码格式**:缩进、空格、换行的统一标准
|
|
|
- **注释规范**:文档注释和行内注释的写法
|
|
|
|
|
|
### 现代C++最佳实践
|
|
|
```cpp
|
|
|
// 使用auto进行类型推导
|
|
|
auto widget = std::make_unique<QWidget>();
|
|
|
|
|
|
// 使用范围for循环
|
|
|
for (const auto& item : container) {
|
|
|
// 处理item
|
|
|
}
|
|
|
|
|
|
// 使用初始化列表
|
|
|
class MyClass {
|
|
|
public:
|
|
|
MyClass(int value) : m_value{value} {} // 统一初始化语法
|
|
|
private:
|
|
|
int m_value;
|
|
|
};
|
|
|
```
|
|
|
|
|
|
## 代码质量度量
|
|
|
|
|
|
### 复杂度指标
|
|
|
- **圈复杂度**:衡量代码逻辑复杂性,建议≤10
|
|
|
- **认知复杂度**:衡量代码理解难度,建议≤15
|
|
|
- **嵌套深度**:控制结构嵌套层数,建议≤4
|
|
|
- **函数长度**:单个函数行数,建议≤50行
|
|
|
|
|
|
### 重复代码检测
|
|
|
```cpp
|
|
|
// 避免代码重复,提取公共函数
|
|
|
void setupButton(QPushButton* button, const QString& text,
|
|
|
const QString& iconPath) {
|
|
|
button->setText(text);
|
|
|
button->setIcon(QIcon(iconPath));
|
|
|
button->setStyleSheet("QPushButton { padding: 8px; }");
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 耦合度分析
|
|
|
- **传入耦合(Ca)**:依赖此模块的其他模块数量
|
|
|
- **传出耦合(Ce)**:此模块依赖的其他模块数量
|
|
|
- **不稳定性(I)**:I = Ce / (Ca + Ce),值越小越稳定
|
|
|
- **抽象度(A)**:抽象类占总类数的比例
|
|
|
|
|
|
## 设计质量原则
|
|
|
|
|
|
### SOLID原则
|
|
|
```cpp
|
|
|
// 单一职责原则 (SRP)
|
|
|
class FileReader {
|
|
|
public:
|
|
|
QString readFile(const QString& filename);
|
|
|
};
|
|
|
|
|
|
class FileWriter {
|
|
|
public:
|
|
|
bool writeFile(const QString& filename, const QString& content);
|
|
|
};
|
|
|
|
|
|
// 开闭原则 (OCP)
|
|
|
class Shape {
|
|
|
public:
|
|
|
virtual double area() const = 0;
|
|
|
virtual ~Shape() = default;
|
|
|
};
|
|
|
|
|
|
class Rectangle : public Shape {
|
|
|
public:
|
|
|
Rectangle(double width, double height) : m_width(width), m_height(height) {}
|
|
|
double area() const override { return m_width * m_height; }
|
|
|
private:
|
|
|
double m_width, m_height;
|
|
|
};
|
|
|
|
|
|
// 里氏替换原则 (LSP)
|
|
|
// 子类对象应该能够替换父类对象而不影响程序正确性
|
|
|
|
|
|
// 接口隔离原则 (ISP)
|
|
|
class Readable {
|
|
|
public:
|
|
|
virtual QString read() = 0;
|
|
|
virtual ~Readable() = default;
|
|
|
};
|
|
|
|
|
|
class Writable {
|
|
|
public:
|
|
|
virtual bool write(const QString& data) = 0;
|
|
|
virtual ~Writable() = default;
|
|
|
};
|
|
|
|
|
|
// 依赖倒置原则 (DIP)
|
|
|
class DataProcessor {
|
|
|
public:
|
|
|
DataProcessor(std::unique_ptr<Readable> reader)
|
|
|
: m_reader(std::move(reader)) {}
|
|
|
|
|
|
void process() {
|
|
|
QString data = m_reader->read();
|
|
|
// 处理数据
|
|
|
}
|
|
|
private:
|
|
|
std::unique_ptr<Readable> m_reader;
|
|
|
};
|
|
|
```
|
|
|
|
|
|
### DRY原则 (Don't Repeat Yourself)
|
|
|
```cpp
|
|
|
// 避免重复代码,使用模板或函数
|
|
|
template<typename T>
|
|
|
void connectSignalSlot(T* sender, void(T::*signal)(),
|
|
|
QObject* receiver, void(QObject::*slot)()) {
|
|
|
QObject::connect(sender, signal, receiver, slot);
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### KISS原则 (Keep It Simple, Stupid)
|
|
|
```cpp
|
|
|
// 简单直接的实现
|
|
|
bool isValidEmail(const QString& email) {
|
|
|
return email.contains('@') && email.contains('.');
|
|
|
}
|
|
|
|
|
|
// 而不是复杂的正则表达式(除非确实需要)
|
|
|
```
|
|
|
|
|
|
## 错误处理和异常安全
|
|
|
|
|
|
### 异常安全等级
|
|
|
```cpp
|
|
|
// 基本保证:不会泄漏资源
|
|
|
class BasicSafety {
|
|
|
public:
|
|
|
void operation() {
|
|
|
auto resource = std::make_unique<Resource>();
|
|
|
// 即使抛出异常,resource也会自动释放
|
|
|
doSomething();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 强异常安全:操作要么成功,要么保持原状
|
|
|
class StrongSafety {
|
|
|
public:
|
|
|
void operation() {
|
|
|
auto backup = m_data; // 备份当前状态
|
|
|
try {
|
|
|
modifyData();
|
|
|
} catch (...) {
|
|
|
m_data = backup; // 恢复原状
|
|
|
throw;
|
|
|
}
|
|
|
}
|
|
|
private:
|
|
|
Data m_data;
|
|
|
};
|
|
|
|
|
|
// 无异常保证:操作绝不抛出异常
|
|
|
class NoThrow {
|
|
|
public:
|
|
|
void operation() noexcept {
|
|
|
// 确保不会抛出异常的操作
|
|
|
}
|
|
|
};
|
|
|
```
|
|
|
|
|
|
### Qt错误处理模式
|
|
|
```cpp
|
|
|
// 使用返回值表示错误状态
|
|
|
enum class FileError {
|
|
|
Success,
|
|
|
FileNotFound,
|
|
|
PermissionDenied,
|
|
|
InvalidFormat
|
|
|
};
|
|
|
|
|
|
class FileManager {
|
|
|
public:
|
|
|
FileError loadFile(const QString& filename, QString& content) {
|
|
|
QFile file(filename);
|
|
|
if (!file.exists()) {
|
|
|
return FileError::FileNotFound;
|
|
|
}
|
|
|
|
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
|
|
return FileError::PermissionDenied;
|
|
|
}
|
|
|
|
|
|
content = file.readAll();
|
|
|
return FileError::Success;
|
|
|
}
|
|
|
};
|
|
|
```
|
|
|
|
|
|
## 性能和内存管理
|
|
|
|
|
|
### RAII (Resource Acquisition Is Initialization)
|
|
|
```cpp
|
|
|
class DatabaseConnection {
|
|
|
public:
|
|
|
DatabaseConnection(const QString& connectionString) {
|
|
|
m_db = QSqlDatabase::addDatabase("QSQLITE");
|
|
|
m_db.setDatabaseName(connectionString);
|
|
|
if (!m_db.open()) {
|
|
|
throw std::runtime_error("Failed to open database");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
~DatabaseConnection() {
|
|
|
if (m_db.isOpen()) {
|
|
|
m_db.close();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 禁止拷贝
|
|
|
DatabaseConnection(const DatabaseConnection&) = delete;
|
|
|
DatabaseConnection& operator=(const DatabaseConnection&) = delete;
|
|
|
|
|
|
// 允许移动
|
|
|
DatabaseConnection(DatabaseConnection&&) = default;
|
|
|
DatabaseConnection& operator=(DatabaseConnection&&) = default;
|
|
|
|
|
|
private:
|
|
|
QSqlDatabase m_db;
|
|
|
};
|
|
|
```
|
|
|
|
|
|
### 智能指针使用指南
|
|
|
```cpp
|
|
|
// unique_ptr:独占所有权
|
|
|
std::unique_ptr<QWidget> createWidget() {
|
|
|
return std::make_unique<QPushButton>("Click me");
|
|
|
}
|
|
|
|
|
|
// shared_ptr:共享所有权
|
|
|
std::shared_ptr<DataModel> getModel() {
|
|
|
static auto model = std::make_shared<DataModel>();
|
|
|
return model;
|
|
|
}
|
|
|
|
|
|
// weak_ptr:避免循环引用
|
|
|
class Parent {
|
|
|
public:
|
|
|
void addChild(std::shared_ptr<Child> child) {
|
|
|
m_children.push_back(child);
|
|
|
child->setParent(shared_from_this());
|
|
|
}
|
|
|
private:
|
|
|
std::vector<std::shared_ptr<Child>> m_children;
|
|
|
};
|
|
|
|
|
|
class Child {
|
|
|
public:
|
|
|
void setParent(std::shared_ptr<Parent> parent) {
|
|
|
m_parent = parent; // 使用weak_ptr避免循环引用
|
|
|
}
|
|
|
private:
|
|
|
std::weak_ptr<Parent> m_parent;
|
|
|
};
|
|
|
```
|
|
|
|
|
|
## 测试和质量保证
|
|
|
|
|
|
### 单元测试最佳实践
|
|
|
```cpp
|
|
|
class TestCalculator : public QObject {
|
|
|
Q_OBJECT
|
|
|
|
|
|
private slots:
|
|
|
void testAddition_data();
|
|
|
void testAddition();
|
|
|
void testDivisionByZero();
|
|
|
|
|
|
private:
|
|
|
Calculator m_calculator;
|
|
|
};
|
|
|
|
|
|
void TestCalculator::testAddition_data() {
|
|
|
QTest::addColumn<int>("a");
|
|
|
QTest::addColumn<int>("b");
|
|
|
QTest::addColumn<int>("expected");
|
|
|
|
|
|
QTest::newRow("positive numbers") << 2 << 3 << 5;
|
|
|
QTest::newRow("negative numbers") << -2 << -3 << -5;
|
|
|
QTest::newRow("mixed numbers") << -2 << 3 << 1;
|
|
|
}
|
|
|
|
|
|
void TestCalculator::testAddition() {
|
|
|
QFETCH(int, a);
|
|
|
QFETCH(int, b);
|
|
|
QFETCH(int, expected);
|
|
|
|
|
|
QCOMPARE(m_calculator.add(a, b), expected);
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 代码审查检查清单
|
|
|
- **功能正确性**:代码是否实现了预期功能
|
|
|
- **边界条件**:是否处理了所有边界情况
|
|
|
- **错误处理**:是否有适当的错误处理机制
|
|
|
- **性能考虑**:是否存在性能瓶颈
|
|
|
- **内存安全**:是否存在内存泄漏或悬空指针
|
|
|
- **线程安全**:多线程环境下是否安全
|
|
|
- **可读性**:代码是否清晰易懂
|
|
|
- **可维护性**:代码是否便于后续维护
|