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

如何从基类创建派生类?能否用模板简化重复的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 14:35:22