第一章:C++工程化概述

大家好,我是你们的老朋友。今天咱们聊聊C++工程化这件事。

说实话,我刚开始写C++的时候,也觉得“工程化”是个挺虚的词。不就是写代码吗?能跑不就行了?后来被现实狠狠教育了几次,才明白——工程化不是花架子,是保命的。

什么是工程化?

工程化,说白了就是用一套规范的方法来管理代码。

你想想看,一个人写个小工具,几百行代码,随便搞搞没问题。但如果是十个人、二十个人一起写一个几十万行的系统呢?没有规矩,那就是灾难。

我在项目中遇到过最典型的例子:一个同事把全局变量到处乱改,结果另一个模块莫名其妙崩溃。查了两天,最后发现是命名冲突。嗯,从那以后,我们团队就老老实实上了命名规范。

工程化的本质:把个人经验转化为团队能力,把偶然成功变成必然结果。

为什么需要工程化?

我总结了几点,都是血泪教训:

  • 可复现性——你昨天能编译通过的代码,今天换台机器就挂了?工程化解决这个问题。
  • 可维护性——三个月后回头看自己的代码,看不懂?工程化让你少掉头发。
  • 可协作性——团队里每个人各写各的,最后合不到一起?工程化就是粘合剂。
  • 可测试性——改了一行代码,不敢上线?工程化给你底气。

我记得有一次,客户现场出了bug,需要紧急修复。因为我们的构建系统是标准化的,从改代码到发布补丁,只用了半小时。要是没有工程化,光环境配置就得折腾半天。

C++工程化的核心要素

这一块我画了个图,方便大家理解:

C++工程化核心要素 代码规范 命名、格式、注释 版本控制 Git、分支策略 构建系统 CMake、Makefile 测试 单元测试、集成测试 文档 API文档、设计文档 五大要素相互支撑,缺一不可 持续集成 / 持续交付 (CI/CD) 工程化 = 规范 + 工具 + 流程

1. 代码规范

代码规范不是用来限制你的,是用来保护你的。

我个人习惯用 Google C++ Style Guide 作为基础,再根据团队情况做微调。比如命名:

// 好的命名
class UserManager {
  void CreateUser(const std::string& name);
  int user_count_;
};

// 糟糕的命名
class um {
  void cu(const std::string& n);
  int uc_;
};

你想想看,三个月后你回来看第二段代码,能看懂吗?反正我看不懂。

我的建议:代码规范要落地,不要写在文档里吃灰。用 clang-format 自动格式化,用 clang-tidy 做静态检查。

2. 版本控制

Git 是标配,这个不用多说。但怎么用,差别很大。

我曾经在一个项目里,看到有人直接把编译好的 .exe 文件提交到仓库里。嗯,那个仓库最后膨胀到了 2 个 G。后来我们加了 .gitignore,才把仓库瘦身下来。

分支策略我推荐 Git Flow 或者 Trunk-Based Development,看团队规模:

策略 适用场景 优点 缺点
Git Flow 大型团队、发布周期长 分支清晰,适合多版本并行 分支多,合并复杂
Trunk-Based 小团队、持续交付 简单,冲突少 对测试要求高

3. 构建系统

C++ 的构建系统,我个人首推 CMake。为什么?跨平台,生态好,社区活跃。

一个简单的 CMakeLists.txt 示例:

cmake_minimum_required(VERSION 3.16)
project(MyProject VERSION 1.0.0)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(my_app main.cpp utils.cpp)

target_include_directories(my_app PRIVATE include)

你看,几行代码就把编译规则说清楚了。比手写 Makefile 省心多了。

注意:不要直接在源码目录里编译。建一个 build 目录,在里面跑 cmake。这样想清理的时候,直接删 build 目录就行。

4. 测试

测试这件事,我以前也觉得麻烦。直到有一次,我改了一个底层函数,结果上层三个模块都出了问题。要是没有单元测试,我根本发现不了。

C++ 常用的测试框架:

  • Google Test——功能最全,文档最完善
  • Catch2——轻量级,header-only
  • Boost.Test——如果你已经在用 Boost

一个简单的 Google Test 示例:

#include <gtest/gtest.h>

int Add(int a, int b) {
  return a + b;
}

TEST(AddTest, PositiveNumbers) {
  EXPECT_EQ(Add(1, 2), 3);
  EXPECT_EQ(Add(10, 20), 30);
}

TEST(AddTest, NegativeNumbers) {
  EXPECT_EQ(Add(-1, -2), -3);
}

测试覆盖率不用追求 100%,但核心逻辑一定要覆盖到。

5. 文档

文档是很多人容易忽略的。代码写完了,文档?再说吧。结果半年后,新同事来了,没人能说清楚某个模块是干嘛的。

我建议至少要有:

  • README——项目简介、如何构建、如何运行
  • API 文档——用 Doxygen 自动生成
  • 设计文档——架构图、关键决策

Doxygen 注释示例:

/**
 * @brief 计算两个整数的和
 * @param a 第一个加数
 * @param b 第二个加数
 * @return 两数之和
 */
int Add(int a, int b);

文档不用写得多华丽,但一定要准确、及时更新。过时的文档比没有文档更可怕。

小结

工程化不是一蹴而就的。我见过很多团队,一开始觉得麻烦,后来尝到甜头就再也回不去了。

你想想看,代码规范、版本控制、构建系统、测试、文档——这五个要素就像五根柱子,撑起了一个可靠的 C++ 项目。少一根,房子就可能塌。

好了,这一章就到这里。记住:工程化不是束缚,是自由。它让你从“这代码能不能跑”的焦虑中解放出来,去关注真正有价值的事情。

一句话总结:工程化 = 规范 + 工具 + 流程,目的是让团队高效协作,让代码可持续演进。

可可精品资料库