如何从基类创建派生类?能否用模板简化重复的createNew实现?
问题描述
现有如下Base基类:
class Base{ public: virtual Base *createNew(){ auto newItem = new Base(); setNew(newItem); return newItem; }; void setNew(Base *item){ item->value = value; }; private: int value; };
多个派生类(如Derive1、Derive2、Derive3)的createNew实现逻辑高度相似,仅类型不同,每个派生类都重复编写了几乎一样的代码:
class Derive1 : public Base{ Derive1 *createNew(){ auto newItem = new Derive1(); setNew(newItem); return newItem; }; void setNew(Derive1 *item){ Base::setNew(item); item->value1 = value1; }; private: int value1; }; class Derive2 : public Base{ Derive2 *createNew(){ auto newItem = new Derive2(); setNew(newItem); return newItem; }; void setNew(Derive2 *item){ Base::setNew(item); item->value2 = value2; }; private: int value2; }; class Derive3 : public Base{ Derive3 *createNew(){ auto newItem = new Derive3(); setNew(newItem); return newItem; }; void setNew(Derive3 *item){ Base::setNew(item); item->value3 = value3; }; private: int value3; }; int main(int argc, char *argv[]) { std::list<Base *> list; list.push_back(new Derive1); list.push_back(new Derive2); list.push_back(new Derive3); list.push_back(new Derive2); list.push_back(new Derive1); std::list<Base *> listNew; for(auto item : list) { listNew.push_back(item->createNew()); } ... //ignore the memory leak. }
想找到一种简便方法,无需在每个派生类中重复编写createNew方法,请问模板能否实现这个需求?
解决方案:使用CRTP模板基类
可以用**奇异递归模板模式(CRTP)**实现代码复用,彻底消除createNew方法的重复编写。核心思路是让派生类继承一个以自身为模板参数的模板基类,在模板基类中统一实现通用的createNew逻辑。
1. 重构基类结构
先修改Base类,移除原有的createNew,然后新增一个模板基类Cloneable,把通用的createNew逻辑放在这里:
#include <list> class Base{ public: virtual ~Base() = default; // 建议添加虚析构,避免内存泄漏 void setNew(Base *item){ item->value = value; }; private: int value; }; template <typename Derived> class Cloneable : public Base { public: Derived* createNew() override { auto newItem = new Derived(); // 调用派生类特有的setNew方法 static_cast<Derived*>(this)->setNew(newItem); return newItem; } };
2. 简化派生类实现
让每个派生类继承Cloneable<Derived>而非直接继承Base,只需要保留子类特有的setNew方法即可:
class Derive1 : public Cloneable<Derive1> { public: void setNew(Derive1 *item){ Base::setNew(item); item->value1 = value1; }; private: int value1; }; class Derive2 : public Cloneable<Derive2> { public: void setNew(Derive2 *item){ Base::setNew(item); item->value2 = value2; }; private: int value2; }; class Derive3 : public Cloneable<Derive3> { public: void setNew(Derive3 *item){ Base::setNew(item); item->value3 = value3; }; private: int value3; };
3. 验证使用效果
原main函数无需任何修改,依然可以正常工作:
int main(int argc, char *argv[]) { std::list<Base *> list; list.push_back(new Derive1); list.push_back(new Derive2); list.push_back(new Derive3); list.push_back(new Derive2); list.push_back(new Derive1); std::list<Base *> listNew; for(auto item : list) { listNew.push_back(item->createNew()); } // 实际代码中需手动释放内存,避免泄漏 }
额外说明
- CRTP的优势:通过静态多态替代部分动态多态逻辑,既实现了代码复用,又避免了重复编写相同方法。
- 虚析构必要性:
Base类添加虚析构后,通过Base*指针释放派生类对象时,能正确调用派生类的析构函数,避免内存泄漏。 - 扩展性:后续新增派生类时,只需继承
Cloneable<NewDerived>并实现子类特有的setNew即可,无需重复编写createNew。
内容的提问来源于stack exchange,提问作者Brett Li
相关产品推荐
相关产品推荐

