载体和多态性C ++(Vectors and polymorphism in C++)

2019-08-31 15:52发布

我有一个棘手的情况。 它的简化形式是这样的

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;  }
};

然后在一类我做这样的事情?

void some_method()
{
    vector<Instruction> v;
    Instruction* i = new Add(1,2,3)
    v.push_back(*i);
}

而在另一个类...

void some_other_method()
{
    Instruction ins = v.back();
    ins.execute();
}

和他们莫名其妙地分享这个指令矢量。 我担心的是我做的“执行”功能的一部分。 它是否行得通呢? 它将保留其添加类型?

Answer 1:

不,不会。

vector<Instruction> ins;

卖场值,而不是引用。 这意味着,不管你怎么但是在那里,教学对象,它会在未来的某个时候被复制。

此外,由于你和分配new ,上面的代码泄漏该对象。 如果你想正确地做到这一点,你就必须做

vector<Instruction*> ins

或者,更好的是:

vector< std::reference_wrapper<Instruction> > ins

我喜欢这个博客帖子解释reference_wrapper

这种行为被称为对象切片。



Answer 2:

所以,你需要某种形式的指针。 一个std::shared_ptr效果很好:

typedef shared_ptr<Instruction> PInstruction;

vector<PInstruction> v;
v.emplace_back(make_shared<Add>());

PInstruction i = v[0];

请记住,PInstruction是引用计数,使PInstruction的拷贝构造函数将创建一个新的“参考”同一个对象。

如果你想引用对象的副本,你将不得不实现clone方法:

struct Instruction
{

   virtual PInstruction clone() = 0;
   ...
}

struct Add
{
    PInstruction clone() { return make_shared<Add>(*this); }
    ...
}

PInstruction x = ...;
PInstruction y = x->clone();

如果性能是比你可以看一个问题std::unique_ptr ,这是有点麻烦,以管理为移动语义总是必需的,但它避免了一些原子操作的成本。

你也可以使用原始指针,并用某种内存池架构的手工管理的内存。

根本的问题是,有一个多态型的编译器不知道子类有多大将是,所以你不能只是有基本类型的载体,因为它不会有被需要的额外空间子类。 出于这个原因,你需要使用通-by-reference语义如上所述。 这个存储的指针到载体中的对象,然后存储关于这取决于该子类中,需要不同尺寸的块的堆的对象。



Answer 3:

不,这是行不通的; 你是“切片”的Add对象,只有将其Instruction部分入阵。 我会建议你做基类的抽象(例如,通过使execute纯虚),使切片给出了一个编译错误,而不是意外的行为。

要获得多态行为,载体需要包含指针的基类。

然后,您就需要小心你如何管理对象本身,因为他们不再包含于载体。 智能指针可以是用于这个有用的; 因为你很可能会被动态分配这些对象,你也应该给基类的虚析构函数,以确保你能正确地将其删除。



Answer 4:

您可能需要做两件事,A:改变“V”,以“矢量”,B类型:与“删除”操作员管理你的记忆。 要回答你的问题,用这种方法,是的,但你只能够访问来自“指令”的界面,如果你知道的东西“说明”指针指向我的类型,如果你需要会建议使用的dynamic_cast访问,比如说,从“添加”的接口。



文章来源: Vectors and polymorphism in C++