C ++中的任务列表(具有多种类型的向量)

时间:2015-09-24 10:54:36

标签: c++ oop

我的目标是填写一份任务清单;每个都是一个包含任务描述的对象。我们将只有两种类型的任务:文件复制和剧目复制。

由于向量不能包含多种类型的对象,我可以创建一个通用的任务类和两个继承该类的对象。

以下是代码:

#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);
}

因为它不起作用,因为run_next期望GenericTaskrtaskftask都被视为通用。

我该怎么办?

我已经尝试在这里和那里添加template,但最终它不起作用,因为我需要知道deque中的类型才能“提取”某些内容。

我可以将this视为答案吗?

4 个答案:

答案 0 :(得分:1)

为什么不创建FileCopyTaskRepertoryCopyTask的对象并将其保存为GenericTask的指针?这样,您就可以利用运行时多态性的强大功能。

像这样:

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)
{
    ....
}

另外,不要忘记将班级run()中的GenericTask方法标记为virtual。还提供virtual析构函数。

答案 1 :(得分:1)

我在你的来源做了一些改变。使用指针将基本fn定义为虚拟和存储对象。你可以在下面查看。

#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);
}

答案 2 :(得分:0)

  

我该怎么办?

请考虑以下步骤:

  • 将GenericTask定义为基类(添加虚拟析构函数,make void run virtual)
  • 覆盖派生类中的run函数
  • 将队列中的元素存储为std :: unique_ptr,而不是“by value”以避免切片问题。
  

我已经尝试过在这里和那里添加模板,但最终它不起作用,因为我需要知道deque中的类型才能“提取”某些内容。

您可以添加boost :: variant作为值,允许存储不相关的类型。

  

我可以考虑这个[这个=答案提出boost :: any作为值类型]作为答案吗?

是。 boost :: variant类似(不同之处在于boost :: any支持设置任何值; boost :: variant仅支持作为variant参数提供的类型的值)。

答案 3 :(得分:-1)

virtual的经典案例。 run方法需要声明为virtual s.t.你实际上是在GenericTask类型的对象上调用RepertoryCopyTask :: run()。

正确完成后,

FileCopyTask t("a", "b");
GenericTask & g = t;
g.run();

会拨打FileCopyTask::run而不是GenericTask::run(原始问题中会这样)。

执行此操作时,您无法将FileCopyTaskRepertoryCopyTask存储在GenericTask的容器中。这是因为它们甚至可能具有不同的尺寸。要解决这个问题,您应该将unique_ptr s存储在某个容器中,即

std::vector<std::unique_ptr<GenericTask> > tasks;

这将是解决问题的正确方法。