首页 > 解决方案 > 如何将值添加到列表>

问题描述

我需要将派生类的元素添加到抽象类的共享指针列表中。

我一直在尝试这个。我知道我正在尝试在下面的示例中创建抽象类的实例,但我不知道如何使其工作。

简化的类如下所示:


using namespace std;

class Abstract
{
  public:
    virtual string toString() const = 0;
};


class A : public Abstract
{
  public:
    A(int a, int b) : a(a), b(b)
    {}
    string toString() const { return "A"; }
  private:
    int a;
    int b;

};
class B : public Abstract
{
  public:
    B(int b) : b(b)
    {}
    string toString() const { return "B"; }
  private:
    int b;
};

问题出在以下课程中:

class Data
{
  public:
    Data(const string & name) : name (name) 
    {}
    Data AddData ( const Abstract & a )
    {
        //Need to fix next line
        l1.push_back(make_shared<Abstract>(a));
        return (*this);   
    }
  private:
    list<shared_ptr<Abstract>> l1;
    string name;
};

我想避免RTII和dynamic_cast。我对不同的解决方案持开放态度。我只需要以某种方式将不同类型的元素存储到单个容器中。

我需要像这样使用类数据:

    Data test("Random Name");

    test.AddData(A(1,2)) 
        .AddData(B(3))
        .AddData(B(4));

标签: c++listpolymorphismabstract-classshared-ptr

解决方案


有什么问题 ?

问题是make_shared<X>它将通过调用X. 在您的情况下,这是不可能的,因为它是一种抽象类型。所以它甚至不会编译。

如果X不是抽象的,它将编译并看起来可以工作。但这会导致创建切片共享对象。

如何解决?

您需要本着原型设计模式的精神使用虚拟克隆功能:

class Abstract
{
  public:
    virtual string toString() const = 0;
    virtual shared_ptr<Abstract> clone() const= 0; 
};

您必须在派生类中覆盖它,例如:

class B : public Abstract
{
  public:
    ...
    shared_ptr<Abstract> clone() const override { return make_shared<B>(*this); } 
  ...
};

然后,您可以利用多态性填充列表:

Data& AddData ( const Abstract & a )   // return preferably a reference
{
    //Need to fix next line
    l1.push_back(a.clone());
    return (*this);   
}

在线演示

补充说明

如果您精通方法链接,我想您会想要AddData()返回一个引用。如果不是,那么每次调用AddData()时,都会创建 的副本Data,这会创建大量不必要的副本。


推荐阅读