【问题标题】:How to instantiate different parent/child classes conditionally?如何有条件地实例化不同的父/子类?
【发布时间】:2017-05-12 16:40:05
【问题描述】:

herehere 发布并回答了类似的问题,但建议的解决方案对我不起作用。

我有三个具有多级继承的类:

class Model
{
public:
    Model();
    template <typename InputModelType>
    void importModel(const InputModelType &m);
    virtual void process(); 
};

class SpecialModel : public Model
{
public:
    SpecialModel();
    template <typename InputModelType>
    void importSpecialModel(const InputModelType &m);
    virtual void process() override; 
};

class SpecialSpecialModel : public SpecialModel
{
public:
    SpecialModel();
    template <typename InputModelType>
    void importSpecialSpecialModel(const InputModelType &m);
    virtual void process() override; 
};

子模型是父模型的特例,可以以更简单的结构存储,因此可以更快地处理。

我想做的是实例化模型,具体取决于用户指定的输入参数model_type,如下所示:

Model* model;
switch(model_type){
case 1:
    model = new SpecialModel;
    model->importSpecialModel(gm);
    break;
case 2:
    model = new SpecialSpecialModel;
    model->importSpecialSpecialModel(gm);
    break;
default:
    model = new Model;
    model->importModel(gm);
    break;
}

model->process();

使用上面的代码,我得到了以下错误:

“模型类”没有名为“importSpecialModel”的成员

“模型类”没有名为“importSpecialSpecialModel”的成员

问题在于,导入函数是模板化的,因此在基类中将它们定义为虚函数然后在子类中覆盖是无效的。

【问题讨论】:

    标签: c++ class oop inheritance


    【解决方案1】:

    您只能使用来自对象的静态类型的函数。 您可以使用派生类型执行以下操作。

    std::unique_ptr<Model> CreateModel(int model_type, const InputModelType &m)
    {
        switch(model_type)
        {
            case 1:
            {
                auto model = std::make_unique<PairwiseMRF>();
                model->importSpecialModel(gm);
                return model; // or std::move(model)
            }
            case 2:
            {
                auto model = std::make_unique<PairwiseMetricMRF>();
                model->importSpecialSpecialModel(gm);
                return model; // or std::move(model)
            }
            default:
            {
                auto model = std::make_unique<Model>();
                model->importModel(gm);
                return model;
            }
        }
    }
    

    然后

    auto model = CreateModel(model_type, gm);
    model->process();
    

    【讨论】:

    • @RSahu: process() 似乎不是模型创建的一部分,这就是我省略它的原因。我添加的用例更类似于 OP 的代码。
    • 感谢您的快速答复!我在提交问题后就看到了它,但我花了一些时间来测试。有用!但似乎 std::make_unique 只是 C++14,不是吗?我必须使用 C++14 进行编译。有没有办法让它在 C++11 中工作?
    • 您仍然可以实现自己的make_unique 或使用unique_ptr 构造函数和new。
    • 谢谢。顺便说一句,使用这个解决方案,变量的释放(例如虚拟析构函数)是没有必要的,对吧?
    • 使用std::unique_ptr,基类应该有虚拟析构函数(但你不必手动调用delete)。使用 shared_ptr ,则不需要。
    【解决方案2】:

    这是the answer by @Jarod42 的变体。您可以通过使用函数指针映射来避免使用switch 语句。

    // Independent functions to import the various model types
    
    std::unique_ptr<Model> importPairwiseMRF(GmType gm)
    {
       auto model = std::make_unique<PairwiseMRF>();
       model->importSpecialModel(gm);
       return model;
    }
    
    std::unique_ptr<Model> importPairwiseMetricMRF(GmType gm)
    {
       auto model = std::make_unique<PairwiseMetricMRF>();
       model->importSpecialSpecialModel(gm);
       return model;
    }
    
    std::unique_ptr<Model> importModel(GmType gm)
    {
       auto model = std::make_unique<Model>();
       model->importModel(gm);
       return model;
    }
    
    // Function to import a model given a model_type and the import data.
    std::unique_ptr<Model> importModel(int model_type, GmType gm)
    {
       // Define a function type that can take gm and return a Model*
       typedef = std::unique_ptr<Model> (*Function)(GmType gm);
    
       // Create a map of the functions known so far.
       std::map<int, Function> theMap =
       {
          {1, importPairwiseMRF},
          {2, importPairwiseMetricMRF},
          {3, importModel}
       };
    
       // If there is a function for the given model_type, use it.
       // Otherwise, return nullptr.
       if ( theMap[model_type] != nullptr )
       {
          return theMap[model_type].second(gm);
       }
       else
       {
          return {};
       }
    }
    

    并将其用作:

    auto model = importModel(model_type, gm);
    if ( model )
    {
       model->process();
    }
    

    【讨论】:

    • 谢谢,但“切换”对我来说很简单。无论如何 +1。
    猜你喜欢
    • 1970-01-01
    • 2019-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    相关资源
    最近更新 更多