Reputation: 695
My aim is to fill a list of task; each will be an object containing the description of the task. Let'say there will be only two type of tasks : file copy and repertory copy.
Since a vector cannot contain more than one type of objects, I though to create a generic task class and two classes that inheritate from that one.
Here is the code :
#include <iostream>
#include <deque>
#include <string>
using namespace std;
class GenericTask{
public :
string config;
GenericTask(string s){
config=s;
}
void run(){
cout<<"Running generic task" <<endl;
}
};
class FileCopyTask : public GenericTask{
public:
string filename;
FileCopyTask(string cf,string fn):GenericTask(cf)
{
filename=fn;
}
void run(){
cout<<"file :"<<filename<<endl;
}
};
class RepertoryCopyTask : public GenericTask{
public:
string repname;
RepertoryCopyTask(string cf,string rn):GenericTask(cf)
{
repname=rn;
}
void run(){
cout<<"repertory : "<<repname<<endl;
}
};
void run_next(deque<GenericTask> &task_list){
task_list.front().run();
task_list.pop_front();
}
int main()
{
RepertoryCopyTask rtask("configuration","/home");
FileCopyTask ftask( "configutation","gile.tex" );
deque<GenericTask> task_list;
task_list.push_back(rtask);
task_list.push_back(ftask);
run_next(task_list);
}
As it, it does not work because run_next
expect a GenericTask
and both rtask
and ftask
are treated as generic.
How should I do ?
I already tried to add template
here and there, but ultimately it does not work because I need to know the type inside the deque
before to "extract" something.
Can I consider this as an answer ?
Upvotes: 0
Views: 1221
Reputation: 82
I made some changes in your source. Defined your base fn as virtual and stored objects with pointers. You can check it below.
#include <iostream>
#include <deque>
#include <string>
using namespace std;
class GenericTask{
public :
string config;
GenericTask(string s){
config=s;
}
virtual void run(){
cout<<"Running generic task" <<endl;
}
};
class FileCopyTask : public GenericTask{
public:
string filename;
FileCopyTask(string cf,string fn):GenericTask(cf)
{
filename=fn;
}
void run(){
cout<<"file :"<<filename<<endl;
}
};
class RepertoryCopyTask : public GenericTask{
public:
string repname;
RepertoryCopyTask(string cf,string rn):GenericTask(cf)
{
repname=rn;
}
void run(){
cout<<"repertory : "<<repname<<endl;
}
};
void run_next(deque<GenericTask*> &task_list){
task_list.front()->run();
task_list.pop_front();
}
int main()
{
RepertoryCopyTask* rtask = new RepertoryCopyTask("configuration","/home");
FileCopyTask* ftask = new FileCopyTask( "configutation","gile.tex" );
deque<GenericTask*> task_list;
task_list.push_back(ftask);
task_list.push_back(rtask);
run_next(task_list);
}
Upvotes: 1
Reputation: 1545
A classical case of virtual
. The run methods need to be declared virtual
s.t. you are actually calling RepertoryCopyTask::run() on an object of type GenericTask.
When done correctly,
FileCopyTask t("a", "b");
GenericTask & g = t;
g.run();
will call FileCopyTask::run
instead of GenericTask::run
(which it would in the original question).
When you did this, you can't store your FileCopyTask
s and RepertoryCopyTask
in a contaianer for GenericTask
. This is because they might even have different size. To get around this, you should store unique_ptr
s for them in some container, i.e.
std::vector<std::unique_ptr<GenericTask> > tasks;
This would be the correct way of solving your problem.
Upvotes: -1
Reputation: 9619
Why not create objects of FileCopyTask
and RepertoryCopyTask
and save them as pointers to GenericTask
? This way you can leverage the power of runtime polymorphism.
Like this:
int main()
{
std::unique_ptr<GenericTask> ftask = std::make_unique<FileCopyTask>("configutation","gile.tex");
std::unique_ptr<GenericTask> rtask = std::make_unique<FileCopyTask>("configuration","/home");
...
}
void run_next(deque<std::unique_ptr<GenericTask> > &task_list)
{
....
}
Also, do not forget to mark the run()
method in class GenericTask
as virtual
. Also provide a virtual
destructor.
Upvotes: 1
Reputation: 27365
How should I do ?
Consider these steps:
void run
virtual)I already tried to add template here and there, but ultimately it does not work because I need to know the type inside the deque before to "extract" something.
You can add a boost::variant as the value, allowing the storage of unrelated types.
Can I consider this [this=answer proposing boost::any as value type] as an answer ?
Yes. boost::variant would be similar (the difference is that boost::any supports setting any value; boost::variant only supports values of the types provided as variant arguments).
Upvotes: 0