如何将值添加到列表<shared_ptr<Abstract>>
How to add values to list<shared_ptr<Abstract>>
我需要将派生 classes 的元素添加到抽象 class.
的共享指针列表中
我一直在尝试这个。我知道我正在尝试在下面的示例中创建抽象 class 的实例,但我不知道如何让它工作。
简化后的 class 看起来像这样:
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:
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。我对不同的解决方案持开放态度。我只需要以某种方式将不同类型的元素存储到单个容器中。
我需要使用 class 这样的数据:
Data test("Random Name");
test.AddData(A(1,2))
.AddData(B(3))
.AddData(B(4));
有什么问题吗?
问题是 make_shared<X>
将通过调用 X
的构造函数来创建共享对象。在您的情况下,这是不可能的,因为它是一种抽象类型。所以它甚至不会编译。
如果 X
不是抽象的,它会编译并且看起来可以工作。但它会导致创建一个 sliced 共享对象。
如何解决?
您需要本着prototype design pattern的精神使用虚拟克隆功能:
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);
}
补充说明
如果您是 method chaining 的行家,我想您会想要 AddData()
到 return 参考。如果不是,那么每次调用 AddData()
时,您都会创建一个 Data
的副本,这会创建大量不必要的副本。
您不能将抽象 class 实例推送到列表。我要么重载了 AddData() 函数,要么使用了模板。
class Data
{
public:
Data(const string & name) : name (name) {}
Data& AddData (const A &a)
{
l1.push_back(make_shared<A>(a));
return (*this);
}
Data& AddData (const B &b)
{
l1.push_back(make_shared<B>(b));
return (*this);
}
private:
list<shared_ptr<Abstract>> l1;
string name;
};
或
class Data
{
public:
Data(const string & name) : name (name) {}
template<typename T>
Data& AddData (const T &a)
{
l1.push_back(make_shared<T>(a));
return (*this);
}
private:
list<shared_ptr<Abstract>> l1;
string name;
};
我需要将派生 classes 的元素添加到抽象 class.
的共享指针列表中我一直在尝试这个。我知道我正在尝试在下面的示例中创建抽象 class 的实例,但我不知道如何让它工作。
简化后的 class 看起来像这样:
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:
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。我对不同的解决方案持开放态度。我只需要以某种方式将不同类型的元素存储到单个容器中。
我需要使用 class 这样的数据:
Data test("Random Name");
test.AddData(A(1,2))
.AddData(B(3))
.AddData(B(4));
有什么问题吗?
问题是 make_shared<X>
将通过调用 X
的构造函数来创建共享对象。在您的情况下,这是不可能的,因为它是一种抽象类型。所以它甚至不会编译。
如果 X
不是抽象的,它会编译并且看起来可以工作。但它会导致创建一个 sliced 共享对象。
如何解决?
您需要本着prototype design pattern的精神使用虚拟克隆功能:
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);
}
补充说明
如果您是 method chaining 的行家,我想您会想要 AddData()
到 return 参考。如果不是,那么每次调用 AddData()
时,您都会创建一个 Data
的副本,这会创建大量不必要的副本。
您不能将抽象 class 实例推送到列表。我要么重载了 AddData() 函数,要么使用了模板。
class Data
{
public:
Data(const string & name) : name (name) {}
Data& AddData (const A &a)
{
l1.push_back(make_shared<A>(a));
return (*this);
}
Data& AddData (const B &b)
{
l1.push_back(make_shared<B>(b));
return (*this);
}
private:
list<shared_ptr<Abstract>> l1;
string name;
};
或
class Data
{
public:
Data(const string & name) : name (name) {}
template<typename T>
Data& AddData (const T &a)
{
l1.push_back(make_shared<T>(a));
return (*this);
}
private:
list<shared_ptr<Abstract>> l1;
string name;
};