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,如果你需要从“添加”中访问界面。