C++ C+中的载体和多态性+;
我的处境很棘手。它的简化形式是这样的C++ C+中的载体和多态性+;,c++,oop,vector,polymorphism,C++,Oop,Vector,Polymorphism,我的处境很棘手。它的简化形式是这样的 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 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);
}
它们以某种方式共享这个指令向量。我关心的是我执行函数的部分。行吗?它会保留其Add类型吗?不,这将不起作用;您正在对
Add
对象进行“切片”,并且仅将其指令
部分插入数组。我建议您将基类抽象化(例如,通过使execute
pure-virtual),这样切片会产生编译错误,而不是意外行为
要获得多态行为,向量需要包含指向基类的指针
然后,您需要注意如何管理对象本身,因为它们不再包含在向量中。智能指针对此可能很有用;由于您可能会动态分配这些对象,因此还应该为基类提供一个虚拟析构函数,以确保您可以正确删除它们。不,不会
vector<Instruction> ins;
或者,更好的是:
vector< std::reference_wrapper<Instruction> > ins
vectorins
我喜欢用这个来解释reference\u wrapper
这种行为称为,因此需要某种指针。一个
std::shared_ptr
工作正常:
typedef shared_ptr<Instruction> PInstruction;
vector<PInstruction> v;
v.emplace_back(make_shared<Add>());
PInstruction i = v[0];
typedef共享\u ptr pin指令;
向量v;
v、 向后放置(使共享());
p指令i=v[0];
请记住,PInstruction是引用计数的,因此PInstruction的复制构造函数将创建对同一对象的新“引用”
如果要创建引用对象的副本,则必须实现克隆方法:
struct Instruction
{
virtual PInstruction clone() = 0;
...
}
struct Add
{
PInstruction clone() { return make_shared<Add>(*this); }
...
}
PInstruction x = ...;
PInstruction y = x->clone();
struct指令
{
虚拟PIN指令克隆()=0;
...
}
结构添加
{
Pinsttruction clone(){return make_shared(*this);}
...
}
P指令x=。。。;
p指令y=x->clone();
如果性能是一个您无法看到的问题,那么由于总是需要移动语义,因此管理起来有点困难,但它避免了一些原子操作的成本
您还可以使用原始指针,并使用某种内存池体系结构手动管理内存
潜在的问题是,要拥有多态类型,编译器不知道子类将有多大,因此不能只拥有基类型的向量,因为它不会拥有子类所需的额外空间。因此,您将需要使用如上所述的按引用传递语义。这会将指向该对象的指针存储在向量中,然后根据子类的需要将该对象存储在不同大小的块中。您可能需要做一些事情,a:将“v”的类型更改为“vector”,B:使用“delete”操作符管理内存。为了回答您的问题,使用这种方法,是的,但您只能从“指令”访问接口,如果您知道“指令”指针指向的对象类型,我建议您使用动态强制转换,如果您需要从访问接口,例如“添加”。,您试过了吗?请阅读。让我编辑一些内容您的
some_method()
每次调用都会泄漏内存。将向量类型更改为指针容器,并删除取消引用(*i)。它会起作用。@user44273:然后使用Boost或TR1中的共享ptr
实现。@user44273您知道为什么按值推送对象不起作用吗?这是这个答案最重要的一点,不是完全的。你能告诉我吗?@user44273阅读关于对象切片的文章。它准确地阐明了你如何处理这个问题的错误,以及这个答案(和其他几个答案)解决这个问题的信封机制。这将比单独的评论更好地解释它。好吧。。。谢谢!我很高兴我没有继续实现这个,几个小时后我的头撞到了墙上。我为内存泄漏道歉。这是一个仓促编写的代码。不幸的是,我不知道是哪种类型。除了这里给出的Add之外,还有Sub、Mul、Div和更多。@user44273不需要道歉,我只是假设了动态的_cast。对向量要非常小心!你必须绝对确定你添加到向量中的任何东西都比向量有更长的生命周期,并且你添加的东西会在某个时候被删除。最好使用向量
。
typedef shared_ptr<Instruction> PInstruction;
vector<PInstruction> v;
v.emplace_back(make_shared<Add>());
PInstruction i = v[0];
struct Instruction
{
virtual PInstruction clone() = 0;
...
}
struct Add
{
PInstruction clone() { return make_shared<Add>(*this); }
...
}
PInstruction x = ...;
PInstruction y = x->clone();