我有一个基类(car
)和一个继承基类(honda
)的类:
class car
{
virtual void polymorphic_class()
{ }
};
class honda : public car
{ };
当我使用下面的代码时,我将我的类转换成一个空指针:
list<car> cars;
honda h;
cars.push_back(h);
honda* h_ptr = dynamic_cast<honda*>(&cars.back());
// h_ptr is NULL
为什么呢?我如何正确地施放我的物体?
答案 0 :(得分:4)
这不起作用的原因是对象切片。 cars
中的对象不再是honda
,而只是汽车。
你需要一个指针或智能指针的向量:
list<car*> cars;
honda h;
cars.push_back(&h);
honda* h_ptr = dynamic_cast<honda*>(cars.back());
我实际上改变了设计并使car
抽象(纯虚拟析构函数或其他东西)。这样你也会得到编译错误。
答案 1 :(得分:2)
多态性适用于指针和引用,而不适用于对象实例。
在这种情况下,您的列表包含car
类型的对象,而不是任何派生类型的对象。当您插入honda
时,它会复制car
部分并忽略其余部分;这有时被称为切片。
对于多态,您可以使用指针列表:
list<car*> cars {new honda};
honda * h_ptr = dynamic_cast<honda*>(cars.back()); // should be a valid pointer
注意:如果您使用我的示例中的new
进行分配,请记住delete
,或者存储智能指针(如std::unique_ptr<car>
)而不是原始指针。您还需要一个虚拟析构函数,以便使用基类指针删除对象。
您可以通过使基类 abstract 来避免切片问题;如果它包含纯虚函数,则不能实例化该类型的对象,只能实例化覆盖这些函数的派生类型:
class car
{
virtual ~car() {}
virtual void do_something() = 0;
};
class honda : public car
{
void do_something() {}
};
如果您实际上不需要抽象接口(例如,如果您只使用dynamic_cast
而不是通过虚函数访问派生类功能),那么您可以使析构函数变为纯虚拟;那么派生类将不必显式覆盖任何东西。必须仍然实现基类析构函数,并且由于语言的怪癖,该实现必须在类定义之外:
class car
{
virtual ~car() = 0;
};
inline car::~car() {}
class honda : public car {};
这是一种有点不寻常的方法,因为通过虚函数的多态性通常更有效,更方便。
答案 2 :(得分:0)
试试这个
list<car*> cars;
honda *h = new honda();
cars.push_back(h);
honda* h_ptr = dynamic_cast<honda*>(cars.back());
这很有效。