Pimpl 设计模式(指针指向实现)

一、背景

c 复制代码
    class TestTreeData: public data::TreeObjectData
    {
    public:
        TestTreeData();
		~TestTreeData();
    protected:
       void InitData()override;
    private:
        class Internal;
        std::unique_ptr<Internal> mTreeList;
    };
    class TestTreeData::Internal
{
public:
    Internal() {

    }
    ~Internal() {

    }
	//求解设定
	Ptr<TestSolutionControlTreeData> SolutionControlTreeData;
};

二、原因

InternalPimpl设计模式 的实现,用于存放 TestTreeData 的所有私有数据,将内部实现与对外接口分离,让外部类保持简洁干净。


逐部分解析

1. class Internal;

  • 仅为前向声明

  • 作用:告诉编译器存在这个类,具体定义后续提供

2. std::unique_ptr<Internal> mTreeList;

  • 管理内部对象的智能指针

  • TestTreeData 唯一的私有成员,结构极简

3. TestTreeData::Internal 实现类

  • 真正存放内部数据的容器

  • 当前存储:SolutionControlTreeData(求解设定树节点数据)

  • 所有私有成员变量、内部状态都放在这里


这种写法的3个核心优势

  1. 头文件干净整洁

外部类看不到内部私有成员,接口清晰

  1. 降低代码耦合

内部依赖的类型不暴露给外部,加快编译速度

  1. 易于扩展维护

新增成员变量只需修改 Internal,不影响外部类结构


直观对比

不使用 Internal(结构混乱)

C++ 复制代码
class TestTreeData: public TreeObjectData
{
private:
    Ptr<TestSolutionControlTreeData> SolutionControlTreeData;
    // 后续会不断新增私有成员...
};

使用 Internal(结构清爽)

C++ 复制代码
class TestTreeData: public TreeObjectData
{
private:
    class Internal;
    std::unique_ptr<Internal> mTreeList;
};

业务层面作用

TestTreeData 作为树数据节点,需要持有求解设定相关数据:

SolutionControlTreeData

为了不将私有数据暴露在外部类中,统一收纳在 Internal 内部类中管理。

三、为啥用std::unique_ptr?

核心原因:std::unique_ptr 是 管理 Internal 内部类对象最安全、最适配 Pimpl 模式 的选择,贴合你的项目场景,优势明确且无多余开销,具体原因(直白不绕弯):

1. 自动管理内存,杜绝泄漏

unique_ptr 会在 TestTreeData 对象销毁时,自动调用 Internal 的析构函数、释放内存,无需你手动写 delete mTreeList,避免忘记清理导致的内存泄漏。

2. 贴合 Pimpl 模式的"唯一所有权"

Internal 是 TestTreeData 专属的内部实现,仅被当前 TestTreeData 对象拥有,不对外共享、不允许拷贝。unique_ptr 恰好保证"唯一所有权",禁止拷贝赋值,完美匹配你的代码设计(内部数据隐藏)。

3. 轻量无性能开销

unique_ptr 是轻量级智能指针,底层实现和裸指针几乎一致,没有额外的引用计数开销,适合树数据类(可能频繁创建/销毁节点),不影响程序运行效率。

4. 支持前向声明(关键适配)

你的代码中 class Internal; 是前向声明(只声明、不定义),unique_ptr 支持将前向声明的类作为模板参数,而 shared_ptr 等其他智能指针会直接编译报错,刚好适配你现有的代码结构。

  1. 无需手动管理 unique_ptr 的释放,析构函数无需额外写 delete mTreeList(手动写反而多余,甚至可能报错)。

  2. 若 TestTreeData 需要支持拷贝/赋值,需手动实现拷贝构造和赋值运算符(unique_ptr 禁止默认拷贝,贴合 Pimpl 模式"隐藏实现"的初衷,一般无需支持)。

  3. Internal 类的析构函数需正常实现(哪怕是空实现),避免 unique_ptr 释放时出现未定义行为。

四、为啥不用shared_ptr?

你的代码场景(前向声明)

cpp 复制代码
class TestTreeData: public data::TreeObjectData
{
private:
    class Internal; // 仅前向声明(无类的具体实现)
    std<Internal> mTreeList; // 正常编译
    // std<Internal> mTreeList; // 直接编译报错
};

为什么 unique_ptr 可以,shared_ptr 不行?

「unique_ptr」:仅需要 "类存在" 的声明(前向声明足够),它的底层不需要知道 Internal 的具体大小、析构细节(编译时不检查,运行时再匹配)。

「shared_ptr」:需要知道 Internal 的具体结构(比如析构函数、内存大小),因为它要管理引用计数、自动释放内存,前向声明只说 "有这个类",没提供这些细节,编译器无法处理,直接报错。

相关推荐
Nuopiane2 小时前
MyPal3(4)
java·开发语言
领小2 小时前
VS2022 MFC对话框应用OLE读写操作excel
c++·excel·mfc
深耕AI2 小时前
【 从零开始的VS Code Python环境配置:uv】
开发语言·python·uv
AI_56782 小时前
RabbitMQ消息队列:高可用集群搭建与消息幂等处理
开发语言·后端·ruby
古城小栈2 小时前
Rust 1.94.0 闪亮登台
开发语言·后端·rust
大母猴啃编程2 小时前
Socket编程UDP
linux·网络·c++·网络协议·udp
SEO-狼术2 小时前
Convert HTML Tables to PDF in Python
开发语言·python·pdf
码云数智-大飞2 小时前
三足鼎立下的抉择:深度解析 Vue、React 与 Angular 的核心差异与选型指南
开发语言
TheLegendMe2 小时前
Python 基础语法练习题
开发语言·python