C ++中的向量和多态性
我有一个棘手的情况。 它的简化forms就是这样的
class Instruction { public: virtual void execute() { } }; class Add: public Instruction { private: int a; int b; int c; public: Add(int x, int y, int z) {a=x;b=y;c=z;} void execute() { a = b + c; } };
然后在一个class里我做一些类似…
void some_method() { vector<Instruction> v; Instruction* i = new Add(1,2,3) v.push_back(*i); }
而在另一class…
void some_other_method() { Instruction ins = v.back(); ins.execute(); }
他们以某种方式共享这个指令向量。 我担心的是我执行“执行”function的部分。 它会起作用吗? 它会保留其添加types?
不,不会的
vector<Instruction> ins;
存储值,而不是引用。 这意味着无论你如何,只要指令对象在那里,它将在未来某个时刻被复制。
此外,由于您正在分配new
,上面的代码泄漏该对象。 如果你想这样做,你必须这样做
vector<Instruction*> ins
或者更好的是:
vector< std::reference_wrapper<Instruction> > ins
我喜欢这个博客post来解释reference_wrapper
这种行为被称为对象切片。
所以你需要一些指针。 一个std::shared_ptr
运作良好:
typedef shared_ptr<Instruction> PInstruction; vector<PInstruction> v; v.emplace_back(make_shared<Add>()); PInstruction i = v[0];
请记住,PInstruction是引用计数的,所以PInstruction的拷贝构造函数将为同一个对象创build一个新的“引用”。
如果你想复制被引用的对象,你必须实现一个克隆方法:
struct Instruction { virtual PInstruction clone() = 0; ... } struct Add { PInstruction clone() { return make_shared<Add>(*this); } ... } PInstruction x = ...; PInstruction y = x->clone();
如果性能是一个问题比你可以看看std::unique_ptr
,这是有点棘手的pipe理,因为总是需要移动语义,但它避免了一些primefaces操作的成本。
您还可以使用原始指针并使用某种内存池体系结构手动pipe理内存。
根本的问题是,有一个多态types的编译器不知道有多大的子类将是,所以你不能只有一个基types的向量,因为它不会有额外的空间需要子类。 出于这个原因,你将需要使用上面描述的通过引用的语义。 这存储了一个指向vector中的对象的指针,然后根据子类的需要将对象存储在堆中不同大小的块中。
不,那不行 您正在“切片” Add
对象,只将其Instruction
部分插入到数组中。 我build议你做基类抽象(例如通过execute
纯虚拟),以便切片给出编译错误,而不是意外的行为。
为了得到多态行为,向量需要包含指向基类的指针。
然后,您将需要小心如何pipe理对象本身,因为它们不再包含在向量中。 智能指针可能对此有用; 因为你可能会dynamic地分配这些对象,所以你也应该给基类一个虚拟析构函数,以确保你可以正确地删除它们。
你可能想做几件事情,A:把“v”的types改为“vector”,B:用“delete”操作符pipe理你的内存。 要回答你的问题,用这种方法,是的,但是你只能从“指令”访问接口,如果你知道“指令”指针所指向的types,我会build议使用dynamic_cast,如果你需要从“添加”中访问界面。