使用堆栈分配的对象将对象存储在异构向量中
您好,
假设我有一个抽象类CA,派生到CA1,CA2和其他人。
我想将这些派生类型的对象放入一个向量中,我将其嵌入到类CB中。为了使多态性正确,我需要存储一个指针向量:
class CB
{
std::vector <CA*> v;
};
现在,我说我有以下主要功能:
int main()
{
CB b;
CA1 a1;
CA2 a2;
b.Store( a1 );
b.Store( a2 );
}
如何以简单的方式编写方法void CB::Store(const CA&)
,因此存储的对象在原始对象被销毁时仍然存在(在上面的简单示例中不会发生)。
我的问题是我需要先在堆上复制对象,然后才能在向量中复制它们的地址,但是如何创建派生类型的对象呢?当然,我可以使用RTTI,搜索所有可能的类型,创建和分配指针,并在将对象推入向量之前将对象复制(通过适当的转换)到已分配的空间中。但这看起来很复杂,不是吗?
有更简单的方法吗?
(并且不使用主要的动态分配!)
答案 0 :(得分:7)
通常,您将提供克隆功能:
struct CA
{
virtual CA *clone(void) const = 0;
virtual ~CA() {} // And so on for base classes.
}
struct CA1 : public CA
{
virtual CA *clone(void) const
{
return new CA1(*this);
}
}
struct CA2 : public CA
{
virtual CA *clone(void) const
{
return new CA2(*this);
}
}
这称为virtual constructor,您可以在运行时构建对象的副本:
void CB::Store(const CA& pObject)
{
CA *cloned = pObject.clone();
}
您应该考虑使用Boost.Pointer Container库。你的代码是:
boost::ptr_vector<CA> objects;
void CB::Store(const CA& pObject)
{
objects.push_back(pObject->clone());
}
现在你不需要自己管理记忆了。该库还尊重克隆功能,并在制作对象副本时调用它。 Tutorial here
答案 1 :(得分:2)
听起来你的抽象类中需要一个clone()函数,派生类将实现它。
class CA
{
public:
virtual ~CA() {}
virtual CA* clone() const = 0;
}
class CA1 : public CA
{
public:
virtual CA *clone() const
{
return new CA1(*this);
}
};
答案 2 :(得分:1)
一种可能性是将Store的论证类型模板化:
class CB
{
public:
template<class T>
void Store(const T& t)
{
v.push_back(new T(t));
}
private:
std::vector <CA*> v;
};
虽然警告:与其他人发布的“clone()”解决方案不同,这很容易被切片。例如,这很好用:
CB b;
CA1 a1;
CA2 a2;
b.Store(a1);
b.Store(a2);
但这不是:
CA1 a1;
CA* a = &a1;
b.Store(*a); //Ouch! this creates a new CA, not a CA1
将受保护的副本提供给CA可防止此类滥用。但是,如果我们进一步将CA1子类化,问题就会出现。