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

基于CRTP的C++模板类多态:如何优雅暴露Copy方法至基类接口

仅通过shared_ptr使用的类设计迭代与优化

初始设计:限制实例化方式

为确保Foo类只能通过shared_ptr使用,将构造函数设为私有,通过静态Create方法和Copy方法提供实例创建途径:

#include <memory>

class Foo {
public:
    static std::shared_ptr<Foo> Create() { 
        return std::shared_ptr<Foo>(new Foo());
    }
    
    std::shared_ptr<Foo> Copy() {
        return std::shared_ptr<Foo>(new Foo(*this));
    }

private:
    Foo() = default;
};

改用CRTP复用方法

为让派生类无需重复实现Create和Copy,将Foo改为CRTP模板类:

#include <memory>

template <class Self>
class Foo {
public:
    template <class... Args>
    static std::shared_ptr<Self> Create(Args&&... args) {
        return std::shared_ptr<Self>(new Self(std::forward<Args>(args)...));
    }

    virtual std::shared_ptr<Self> Copy() {
        return std::shared_ptr<Self>(new Self(*this));
    }

private:
    Foo() = default;
};

class Bar : public Foo<Bar> {};

添加非模板基类定义统一接口

需要一个非模板基类FooBase来定义所有派生类的共享接口,调整后代码如下:

#include <memory>

class FooBase {
public:
    virtual void DoSomething() =0;
};

template <class Self>
class Foo : public FooBase {
public:
    template <class... Args>
    static std::shared_ptr<Self> Create(Args&&... args) {
        return std::shared_ptr<Self>(new Self(std::forward<Args>(args)...));
    }

    virtual std::shared_ptr<Self> Copy() {
        return std::shared_ptr<Self>(new Self(*this));
    }

    virtual void DoSomething() override { }

private:
    Foo() = default;
};

class Bar : public Foo<Bar> {
public:
    virtual void DoSomething() override { }
};

问题:将Copy方法暴露到基类的优雅实现

当前通过改名(CopyBase)实现基类对复制能力的暴露不够优雅,可利用C++虚函数覆盖与静态转型,实现同名Copy方法在基类和派生类中返回对应类型的shared_ptr:

优化实现

#include <memory>

class FooBase {
public:
    virtual void DoSomething() = 0;
    // 基类声明纯虚Copy方法,返回基类的shared_ptr
    virtual std::shared_ptr<FooBase> Copy() const = 0;
};

template <class Self>
class Foo : public FooBase {
public:
    template <class... Args>
    static std::shared_ptr<Self> Create(Args&&... args) {
        return std::shared_ptr<Self>(new Self(std::forward<Args>(args)...));
    }

    // 派生类专属的Copy方法,返回Self类型的shared_ptr
    std::shared_ptr<Self> Copy() const {
        return std::static_pointer_cast<Self>(FooBase::Copy());
    }

    // 实现基类的纯虚Copy方法
    std::shared_ptr<FooBase> Copy() const override {
        return std::shared_ptr<Self>(new Self(*static_cast<const Self*>(this)));
    }

    virtual void DoSomething() override {}

private:
    Foo() = default;
};

class Bar : public Foo<Bar> {
public:
    void DoSomething() override {}
};

优化说明

  • 基类FooBase中声明纯虚的Copy方法,返回std::shared_ptr<FooBase>,确保所有派生类都实现复制能力;
  • CRTP模板类Foo中实现基类的虚Copy方法,同时提供同名非虚Copy方法,通过static_pointer_cast将基类指针转为派生类指针,供具体类调用时返回正确类型的shared_ptr;
  • 通过FooBase指针调用Copy时,会调用虚函数返回基类指针;通过具体派生类(如Bar)的指针调用Copy时,会调用非虚版本返回派生类指针,无需修改方法名。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 19:10:47