基于CRTP的C++模板类多态:如何优雅暴露Copy方法至基类接口
初始设计:限制实例化方式
为确保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
相关产品推荐
相关产品推荐

