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

无需转发函数,为已有C++类适配接口的实现方案

在C++中无需手动转发函数适配已有类到接口的优雅方案

在C#中,我们可以通过让派生类同时继承已有类和接口,无需修改原类就能完成接口适配,实现非常简洁:

interface IPermissions
{
   bool CanView();
   bool CanUpdate();
   bool CanDelete();
}

class Concrete
{
   public bool CanView() { return true; }
   public bool CanUpdate() { return true; }
   public bool CanDelete() { return true; }
}

class Record : Concrete, IPermissions
{
}

之后就能直接将Record实例赋值给接口类型并调用方法:

IPermissions record = new Record();
record.CanView();

但在C++中,由于缺乏类似的隐式接口适配机制,通常只能手动编写转发函数来实现:

class IPermissions
{
public:
    virtual bool CanView() = 0;
    virtual bool CanUpdate() = 0;
    virtual bool CanDelete() = 0;
};

class Concrete
{
public:
    bool CanView() { return true; }
    bool CanUpdate() { return true; }
    bool CanDelete() { return true; }
};

class Record : public Concrete, public IPermissions
{
public:
    bool CanView() override { return Concrete::CanView(); }
    bool CanUpdate() override { return Concrete::CanUpdate(); }
    bool CanDelete() override { return Concrete::CanDelete(); }
};

当无法修改Concrete类(比如属于第三方维护的代码)时,手动编写转发不仅繁琐,还容易因遗漏方法导致错误。以下是两种无需手动编写转发的优雅实现方案:

方案一:固定接口的模板适配器

编写针对IPermissions接口的模板适配器类,自动生成转发逻辑,避免重复代码:

// 适配IPermissions接口的模板类
template<typename Impl>
class PermissionsAdapter : public IPermissions, public Impl
{
public:
    // 继承实现类的所有构造函数
    using Impl::Impl;

    // 自动转发接口方法到实现类
    bool CanView() override { return Impl::CanView(); }
    bool CanUpdate() override { return Impl::CanUpdate(); }
    bool CanDelete() override { return Impl::CanDelete(); }
};

// 使用示例
int main() {
    PermissionsAdapter<Concrete> record;
    IPermissions* ptr = &record;
    ptr->CanView();
    return 0;
}

这种方案和原问题中Record类的结构一致,通过多重继承实现,完全贴合C#的适配逻辑,且无需手动编写每个方法的转发代码。

方案二:成员持有式适配器(避免多重继承)

如果担心多重继承带来的潜在问题,可以将实现类作为成员持有,结合C++20的std::bind_front绑定方法:

#include <functional>
#include <utility>

class IPermissions
{
public:
    virtual bool CanView() = 0;
    virtual bool CanUpdate() = 0;
    virtual bool CanDelete() = 0;
    virtual ~IPermissions() = default;
};

template<typename Impl>
class PermissionsAdapter : public IPermissions
{
private:
    Impl impl_;
    // 绑定实现类的方法到函数对象
    std::function<bool()> can_view_ = std::bind_front(&Impl::CanView, &impl_);
    std::function<bool()> can_update_ = std::bind_front(&Impl::CanUpdate, &impl_);
    std::function<bool()> can_delete_ = std::bind_front(&Impl::CanDelete, &impl_);

public:
    // 转发实现类的构造参数
    template<typename... Args>
    PermissionsAdapter(Args&&... args) : impl_(std::forward<Args>(args)...) {}

    bool CanView() override { return can_view_(); }
    bool CanUpdate() override { return can_update_(); }
    bool CanDelete() override { return can_delete_(); }
};

// 使用示例
int main() {
    PermissionsAdapter<Concrete> record;
    IPermissions* ptr = &record;
    ptr->CanView();
    return 0;
}

这种方式避免了多重继承,同时依然无需手动编写转发逻辑,适合对多重继承有顾虑的场景。

注意事项

  • 两种方案都无需修改原有Concrete类,完全符合需求;
  • 若接口方法包含参数或非void返回值,只需对应调整适配器中的转发逻辑即可;
  • 模板方案编译期完成代码生成,不会带来额外运行时开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 21:54:54