Reputation: 1586
Similar questions were posted and answered here and here but the proposed solutions don't work for me.
I have three classes with multilevel inheritance:
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;
};
The child model is a special case of the parent model and can be stored in a simpler structure and thus, can be processed faster.
What I would like to do is to instantiate the model, depending on an input parameter model_type
that is specified by the user, something like this:
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();
Using the above code, I got the following errors:
‘class Model’ has no member named ‘importSpecialModel’
‘class Model’ has no member named ‘importSpecialSpecialModel’
The problem is that, the import functions are templated, therefore it is not valid to define them as virtual functions in the base class and then override in the child class.
Upvotes: 1
Views: 330
Reputation: 206627
This is a variation of the answer by @Jarod42. You can avoid using a switch
statement by using a map of function pointers.
// 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 {};
}
}
And use it as:
auto model = importModel(model_type, gm);
if ( model )
{
model->process();
}
Upvotes: 1
Reputation: 217448
You can only use function from the static type of the object. You may do the following which use the derived type.
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;
}
}
}
And then
auto model = CreateModel(model_type, gm);
model->process();
Upvotes: 5