mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
2173 字
6 分钟
从Python到C++入门与团队协作笔记
2026-04-29

背景:深度学习算法落地时,往往先用 Python 验证原型,再用 C++ 封装为工程模块。本文记录从 Python 思维转向 C++ 工程化开发的入门路径,以及在公司 SVN 环境下协同开发的实操要点。
适用场景:点云处理(PCL)、Windows DLL 封装、Visual Studio 2022 环境。


一、为什么需要 C++:Python 与 C++ 的工程化差异#

维度Python(算法原型)C++(工程落地)
执行方式解释执行,依赖解释器编译为机器码,独立运行
类型系统动态类型,运行时推断静态类型,编译期检查
内存管理自动垃圾回收(GC)手动管理 / 智能指针 / RAII
多线程GIL 锁限制真并行原生多线程,无锁
依赖管理pip / conda 一键安装头文件(.h)+ 库文件(.lib/.dll)+ 手动链接
部署形态脚本 + 环境可执行文件 / 动态链接库(DLL)
协同开发Git 为主公司老项目常用 SVN

核心结论:C++ 不是“更难的 Python”,而是面向编译器和团队协作的语言。我的目标不是写“能跑的 C++”,而是写别人能接进去、能维护、能调试的 C++


二、开发环境认知:先认清工具链#

1. Visual Studio 2022(IDE)≠ VS Code(编辑器)#

  • VS Code:轻量编辑器,适合写脚本、看代码。但打不开 .sln 工程,无法直接编译 Windows DLL。
  • Visual Studio 2022:完整的 C++ 集成开发环境,负责编译、链接、调试、内存检测。
  • 你的选择:日常写代码可以在 VS Code,但编译和调试必须在 VS2022

2. PCL(Point Cloud Library)#

  • 点云处理的“OpenCV”,提供 pcl::PointCloudpcl::VoxelGridpcl::ConvexHull 等组件。
  • 安装后会有大量头文件和 .lib 文件,需要在 VS 的“项目属性”中配置包含目录和库目录。

3. TortoiseSVN + TortoiseMerge#

  • TortoiseSVN:Windows 资源管理器右键直接操作 SVN(检出、更新、提交)。
  • TortoiseMerge:解决代码冲突时的三路合并工具(左:你的代码 / 右:服务器代码 / 下:合并结果)。

三、C++ 核心概念速通(Python 视角)#

1. 编译流程:代码如何变成可执行文件#

Python 是解释型,直接 python main.py 就跑。C++ 必须经历:

.cpp 源文件 → 编译器 → .obj 目标文件 → 链接器 → .exe / .dll

  • 编译:检查语法,生成机器码(.obj)。
  • 链接:把多个 .obj 和外部库(.lib)拼成最终文件。
  • 你的动作:在 VS2022 里按 Ctrl + Shift + B(生成),就是在执行编译+链接。

2. 头文件(.h)与实现文件(.cpp)的分离#

Python 一个 .py 文件搞定所有。C++ 通常拆成两个文件:

文件作用类比 Python
.h(头文件)声明接口:类名、函数名、参数类型__init__.py 里的 import 列表
.cpp(实现文件)定义实现:函数体、算法逻辑.py 文件里的具体函数代码

为什么分离?

  • 编译器需要知道“有哪些函数”,但不需要知道“函数怎么实现”就能编译其他文件。
  • 主管调用你的 DLL 时,只需要你的 .h 头文件

3. 内存管理:从“自动回收”到“自己负责”#

Python 中 numpy.zeros() 用完不用管。C++ 中:

方式语法生命周期风险
栈对象int a;函数结束自动销毁无,但容量小
堆对象(裸指针)new / delete手动控制极易内存泄漏
智能指针std::shared_ptr / std::unique_ptr引用计数归零自动销毁推荐
PCL 专用pcl::PointCloud<PointT>::PtrPCL 封装的智能指针点云开发首选

血泪原则:写 PCL 代码时,永远用 ::Ptr,绝不写裸 new

4. 命名空间(namespace):避免名字撞车#

Python 用 import numpy as np 隔离。C++ 用 namespace

namespace CarriageSegment {
class Segmentor { ... };
} // 使用时:CarriageSegment::Segmentor seg;

四、从 Python 到 C++ 的语法对照表#

PythonC++头文件
list / numpy.arraystd::vector<float><vector>
dictstd::map<std::string, float><map>
numpy.ndarray (矩阵运算)Eigen::MatrixXf<Eigen/Core>
open3d.geometry.PointCloudpcl::PointCloud<pcl::PointXYZ><pcl/point_types.h>
class MyClass:class MyClass { public: ... };
def func(a: str) -> float:float func(const std::string& a);
try / excepttry / catch (std::exception& e)<stdexcept>
print()std::cout << "text" << std::endl;<iostream>
Nonenullptr
True / Falsetrue / false

五、封装 DLL:给主管一个“黑盒”#

  • 把算法打包成 .dll + .lib + .h,主管看不到源码,只能调用接口。
  • 更新算法时,替换 .dll 即可,主程序无需重新编译。

2. 接口设计原则#

  1. 只暴露标准类型:用 std::stringstd::vectorfloat,不暴露 PCL 类型。
  2. 类封装InitializeProcessRelease 三段式生命周期。
  3. C++ 名称修饰(mangling):用 extern "C" 或统一宏,防止编译后函数名被改写。

3. 核心宏:__declspec(dllexport/dllimport)#

#ifdef CARRIAGE_EXPORTS
#define CARRIAGE_API __declspec(dllexport) // 编译 DLL 时导出
#else
#define CARRIAGE_API __declspec(dllimport) // 主管使用时导入
#endif

4. 完整接口代码(可直接复制)#

carriage_api.h

#pragma once
#include <string>
#include <vector>
#ifdef CARRIAGE_EXPORTS
#define CARRIAGE_API __declspec(dllexport)
#else
#define CARRIAGE_API __declspec(dllimport)
#endif
namespace CarriageSegment {
struct Point3D {
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
};
struct CarriageInfo {
float volume_m3 = 0.0f; // 体积(立方米)
bool success = false; // 是否成功
std::string error_msg; // 错误信息
};
class CARRIAGE_API Segmentor {
public:
bool Initialize(const std::string& config_path);
CarriageInfo Process(const std::string& pcd_file_path);
void Release();
};
} // namespace CarriageSegment

carriage_impl.cpp

#define CARRIAGE_EXPORTS // 必须在 include 之前定义!
#include "carriage_api.h"
#include <iostream>
// 这里后续引入 PCL 头文件
// #include <pcl/io/pcd_io.h>
// #include <pcl/filters/voxel_grid.h>
namespace CarriageSegment {
bool Segmentor::Initialize(const std::string& config_path) {
// TODO: 加载配置、初始化 PCL 对象
std::cout << "[Init] Config: " << config_path << std::endl;
return true;
}
CarriageInfo Segmentor::Process(const std::string& pcd_file_path) {
CarriageInfo info;
// TODO: 替换为真实 PCL 处理逻辑
// 1. 加载 PCD
// 2. 体素滤波
// 3. 分割车厢
// 4. 计算体积
info.volume_m3 = 42.0f; // 占位假数据
info.success = true;
return info;
}
void Segmentor::Release() {
// TODO: 清理资源
std::cout << "[Release] Resources cleaned." << std::endl;
}
} // namespace CarriageSegment

六、团队协作与 SVN 实操#

1. TortoiseSVN 核心操作(右键菜单)#

操作右键路径使用时机
检出(Checkout)SVN 检出...第一次拉项目
更新(Update)SVN 更新每天开工前必做
提交(Commit)SVN 提交...功能完成后
查看修改TortoiseSVN → 检查修改提交前自查
显示日志TortoiseSVN → 显示日志查看历史记录
解决冲突TortoiseSVN → 解决...冲突后调用 TortoiseMerge

2. SVN 与 Git 的习惯差异#

  1. 新增文件必须 Add:SVN 不会自动跟踪新 .cpp / .h,右键 → TortoiseSVN → 增加
  2. 提交前必须 Update:先拉最新代码,再提交,减少冲突。
  3. 提交信息写清楚
    [车厢分割] 添加 DLL 接口头文件,定义 Segmentor 类
    [车厢分割] 实现空壳 Process 函数,返回占位体积

3. TortoiseMerge 解决冲突#

  1. 右键冲突文件 → TortoiseSVN → 编辑冲突
  2. 界面布局:
    • 左侧:你的本地修改(Working)
    • 右侧:服务器最新版本(Theirs)
    • 下方:合并结果(Merged),手动选择保留左/右。
  3. 保存后,右键 → TortoiseSVN → 解决,标记冲突已处理。

七、实战:VS2022 新建 DLL 项目步骤#

1. 创建项目#

文件 → 新建 → 项目 → 搜索"动态链接库(DLL)"
→ 名称:CarriageSegment → 确定

2. 清理自动生成的无用文件#

删除:dllmain.cppframework.hpch.cpp(如果不用预编译头)。

3. 添加你的文件#

右键项目 → 添加新建项

  • carriage_api.h
  • carriage_impl.cpp

4. 配置项目属性(关键)#

右键项目 → 属性

  1. 配置属性 → 常规 → 配置类型:确认是动态库(.dll)
  2. C/C++ → 预处理器 → 预处理器定义:添加 CARRIAGE_EXPORTS
  3. VC++ 目录 → 包含目录:添加 PCL 的 include 路径(如 C:\Program Files\PCL 1.13.1\include)。
  4. VC++ 目录 → 库目录:添加 PCL 的 lib 路径。
  5. 链接器 → 输入 → 附加依赖项:添加用到的 PCL .lib 文件(Release 模式):
    pcl_common.lib
    pcl_io.lib
    pcl_filters.lib
    pcl_segmentation.lib
    pcl_surface.lib

5. 编译与产出#

  • 平台选 x64(不要 x86)。
  • Ctrl + Shift + B 生成。
  • 产出在 x64\Release\
    • CarriageSegment.dll → 运行时依赖
    • CarriageSegment.lib → 编译时链接
    • carriage_api.h → 给主管 include

八、调试与排错速查#

1. VS 调试快捷键#

快捷键功能
F5启动调试
F10单步跳过(不进入函数内部)
F11单步进入(跟进函数)
F9设置/取消断点
Shift + F5停止调试
Ctrl + Shift + B生成解决方案(编译+链接)

2. 内存泄漏检测#

main() 或测试程序中加入:

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
int main() {
// ... 你的代码 ...
_CrtDumpMemoryLeaks(); // 程序退出时打印泄漏报告
return 0;
}

如果输出窗口显示 Detected memory leaks!,说明有 newdelete

3. 常见编译错误#

错误信息原因解决
LNK2019: 无法解析的外部符号函数声明了但没实现 / 没链接 .lib检查 .cpp 是否加入工程,链接器是否加了库
C1083: 无法打开包括文件头文件路径没配置检查 VC++ 目录 → 包含目录
MSB8020: 找不到工具集VS 版本不匹配右键项目 → 重定向项目 → 选 2022
模块计算机类型“x64”与目标计算机类型“X86”冲突平台选错工具栏改成 x64

九、给新手的行动清单#

  1. 装环境:安装 VS2022 Community,勾选“使用 C++ 的桌面开发”。
  2. 问同事:PCL 安装路径、公司代码 SVN 地址、现有 .sln 在哪。
  3. 拉代码:TortoiseSVN 检出公司项目,双击 .sln 升级,编译通过现有工程。
  4. 建模块:在公司解决方案里新建 CarriageSegment DLL 项目,复制本文接口代码。
  5. 跑通空壳:编译出 .dll + .lib,写测试 main.cpp 调用成功。
  6. 填算法:把 Python 的体素法/切片法逐步翻译成 C++ PCL 代码。

结语#

从 Python 到 C++,最大的障碍不是语法,而是工程思维的转变:

  • 从“脚本跑通就行”到“编译通过、接口稳定、内存安全”。
  • 从“自己写自己看”到“同事能接进去、能 Review、能维护”。

先让接口跑起来,再填算法。先让 DLL 编译通过,再优化精度。独立开发可以,但接口要尽早和同事对齐

博客源码已整理完毕,可直接复制到 Markdown 编辑器发布。

---
这份笔记可以直接贴到你的静态博客里。如果你需要,我还可以再生成一份**配套的最小可编译代码包**(`carriage_api.h` + `carriage_impl.cpp` + `test_main.cpp` + `CMakeLists.txt` 或 `.vcxproj` 配置说明),方便读者下载对照。需要吗?
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

从Python到C++入门与团队协作笔记
https://fredsblog-2dc.pages.dev/posts/note-c-py2cppcoop/
作者
Fredzhe
发布于
2026-04-29
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时