如何无需dynamic_cast或逐类实现createCopy,从基类指针创建对象副本?
问题描述
我有一个基类,还有大量继承自该基类的派生类,现在想创建对象的副本。有没有办法不用dynamic_cast,也不用在每个派生类里实现createCopy函数,就能从基类指针推导出它指向对象的实际类型?示例代码如下:
class Base { public: Base(){}; virtual ~Base() = default; virtual void fun() = 0; Base *createCopy() { return new /*some way to deduct real "this" type */ } }; class Derived1 : public Base { public: Derived1() : Base(){}; virtual void fun() { /* impl */ }; }; class Derived2 : public Base { public: Derived2() : Base(){}; virtual void fun() { /* impl */ }; }; /* Derived3 - Derived8999 implementation*/ class Derived9000 : public Base { public: Derived9000() : Base(){}; virtual void fun() { /* impl */ }; }; int main() { Base *pObj = new Derived9000; // pObj type is Derived9000* Base *pCopy = pObj->createCopy(); // pCopy type is Derived9000* }
解决方案
用**CRTP(奇异递归模板模式)**就能解决这个问题,只需要做一次基类封装,所有派生类无需单独实现拷贝函数,也完全不需要使用dynamic_cast。
具体实现步骤:
- 在原始
Base类中声明纯虚的createCopy接口 - 定义一个模板基类
BaseCRTP,继承自Base,并在其中实现createCopy——通过模板参数获取派生类的真实类型,直接创建对应类型的副本 - 所有派生类继承
BaseCRTP,并将自身类型作为模板参数传入
修改后的完整代码如下:
class Base { public: Base() = default; virtual ~Base() = default; virtual void fun() = 0; // 声明纯虚拷贝接口 virtual Base* createCopy() const = 0; }; // CRTP模板基类,负责实现拷贝逻辑 template<typename Derived> class BaseCRTP : public Base { public: Base* createCopy() const override { // 利用模板参数确定真实类型,调用拷贝构造函数 return new Derived(static_cast<const Derived&>(*this)); } }; // 派生类只需继承BaseCRTP并传入自身类型 class Derived1 : public BaseCRTP<Derived1> { public: Derived1() = default; void fun() override { /* 具体实现 */ } }; class Derived2 : public BaseCRTP<Derived2> { public: Derived2() = default; void fun() override { /* 具体实现 */ } }; /* Derived3 - Derived8999 都按上述方式实现 */ class Derived9000 : public BaseCRTP<Derived9000> { public: Derived9000() = default; void fun() override { /* 具体实现 */ } }; int main() { Base* pObj = new Derived9000; Base* pCopy = pObj->createCopy(); // pCopy实际指向Derived9000类型对象 // 清理资源 delete pObj; delete pCopy; return 0; }
方案优势
- 无重复代码:所有派生类无需编写
createCopy,仅需修改继承的基类,适配几千个派生类毫无压力 - 编译期确定类型:完全避免运行时类型转换的开销,效率更高
- 保留多态特性:基类指针依然能正确调用对应派生类的拷贝逻辑
注意事项
- 确保派生类拥有合适的拷贝构造函数:默认拷贝构造函数适用于简单场景,若涉及动态分配资源,需自行实现深拷贝逻辑,CRTP模板会自动调用该构造函数
内容的提问来源于stack exchange,提问作者Caboom Bom
相关产品推荐
相关产品推荐

