You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从注入的策略模式中调用PIMPL实现类的成员函数

解决方案

你选择的通过std::function传递成员方法的方案是完全可行的,既不会暴露Impl内部接口,也不需要对现有WorldTraversal类做大的重构,只需要修正现有代码的几个语法问题即可:

现有代码的错误点

  • 成员函数的std::bind语法错误:绑定非静态成员函数时,第一个参数需要是成员函数的完整地址,第二个参数是对应类实例的指针/引用
  • setStrategy方法参数类型不匹配:入参声明为ITraversalStrategy右值引用,但实际传入的是std::unique_ptr<ITraversalStrategy>
  • 缺少ITraversalStrategy基类定义,且基类没有声明虚析构函数会导致内存释放异常
  • 类定义末尾缺少分号等基础语法问题

修正后的可运行代码

#include <memory>
#include <functional>

// 先声明策略基类
class ITraversalStrategy
{
public:
    using ProcessPath = std::function<void()>;
    using ExecutePath = std::function<void()>;
    virtual void apply(ProcessPath processPath, ExecutePath executePath) = 0;
    virtual ~ITraversalStrategy() = default; // 必须加虚析构避免内存泄漏
};

class WorldTraversal
{
public:
    // 修正参数类型,接收unique_ptr<策略>
    void setStrategy(std::unique_ptr<ITraversalStrategy> strategy) { 
        m_impl->traversalStrategy = std::move(strategy); 
    }
    void execute()
    {
        // 修正bind语法:第一个参数是成员函数的完整地址,第二个参数是Impl实例指针
        m_impl->traversalStrategy->apply(
            std::bind(&WorldTraversal::Impl::processPath, m_impl.get()),
            std::bind(&WorldTraversal::Impl::executePath, m_impl.get())
        );
    }

    WorldTraversal(); // 需显式声明构造析构,适配PIMPL的 unique_ptr 要求
    ~WorldTraversal();
private:
    struct Impl;
    std::unique_ptr<Impl> m_impl;
};

// IMPL定义
struct WorldTraversal::Impl
{
    void processPath();
    void executePath();
    std::unique_ptr<ITraversalStrategy> traversalStrategy;
};

// 实现WorldTraversal的构造和析构,放在Impl定义之后
WorldTraversal::WorldTraversal() : m_impl(std::make_unique<Impl>()) {}
WorldTraversal::~WorldTraversal() = default;

// 实现Impl的方法
void WorldTraversal::Impl::processPath() {}
void WorldTraversal::Impl::executePath() {}

// 具体策略实现
class GroundTraversal : public ITraversalStrategy
{
public:
    void apply(ProcessPath processPath, ExecutePath executePath) override
    {
        processPath();
        executePath();
    }
};

int main()
{
    WorldTraversal worldTraversal;
    worldTraversal.setStrategy(std::make_unique<GroundTraversal>());
    worldTraversal.execute();
    return 0;
}

方案说明

  • 传递std::function的方式不会暴露Impl的任何内部细节,策略侧只能拿到两个可调用对象,完全不知道其内部关联的是Impl的成员函数,符合接口隔离的要求
  • 不需要给策略类增加友元声明,也不需要修改WorldTraversal的公共接口,适配你不能大量重构现有类的限制
  • std::bind绑定unique_ptr的原始指针是安全的:apply方法是在WorldTraversal::execute的调用栈内同步执行,执行过程中m_impl肯定是存活状态,不会出现悬垂指针问题

内容的提问来源于stack exchange,提问作者FMunkee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 15:24:03