您是否必须传递删除new返回的相同指针,或者您是否可以将指针传递给其中一个类基类型?例如:
class Base
{
public:
virtual ~Base();
...
};
class IFoo
{
public:
virtual ~IFoo() {}
virtual void DoSomething() = 0;
};
class Bar : public Base, public IFoo
{
public:
virtual ~Bar();
void DoSomething();
...
};
Bar * pBar = new Bar;
IFoo * pFoo = pBar;
delete pFoo;
当然这大大简化了。我真正想要做的是创建一个充满boost :: shared_ptr的容器,并将其传递给一些代码,这些代码在完成后将从容器中删除它。这段代码对Bar或Base的实现一无所知,并且依赖于shared_ptr析构函数中隐含的delete运算符来做正确的事。
这可能有用吗?我的直觉说不,因为指针不会有相同的地址。另一方面,dynamic_cast< Bar *>应该工作,所以编译器正在存储足够的信息来解决它。
<小时/> 感谢您的帮助,所有回答和评论的人。我已经知道虚拟析构函数的重要性,如我的例子所示;看到答案之后我给了它一点思考,并意识到虚拟析构函数的完整原因就是这个确切的场景。因此它必须工作。由于没有将指针转换回原件的可见方法,我被抛出了。多一点思考让我相信有一种看不见的方法,并且我推断出析构函数正在返回删除的真正指针以释放。当我在~Base中看到这一行时,调查来自Microsoft VC ++的编译代码证实了我的怀疑:
mov eax, DWORD PTR _this$[ebp]
跟踪汇编程序显示这是传递给delete函数的指针。神秘解决了。
我修复了将示例添加到IFoo的虚拟析构函数,这是一个简单的疏忽。再次感谢所有指出的人。
答案 0 :(得分:55)
是的,它会起作用,当且仅当基类析构函数是虚拟的时,你已经为Base
基类而不是IFoo
基类做了类。如果基类析构函数是虚拟的,那么当你在基类指针上调用operator delete
时,它会使用动态调度来找出如何通过在虚函数表中查找派生类析构函数来删除对象。
在你的多重继承的情况下,它只有在你删除它的基类有一个虚拟析构函数时才有效;可以让其他基类没有虚拟析构函数,但前提是你不尝试通过其他基类指针删除任何派生对象。
答案 1 :(得分:3)
这与您给出的示例无关,但由于您在删除其拥有的对象时提到您对shared_ptr
的行为真的感兴趣,因此您可能有兴趣使用shared_ptr
' ''删除'。
如果shared_ptr
拥有的对象在被删除时需要特殊处理,您可以为任何特定shared_ptr<>
指定“删除者”。删除器不是类型的一部分,它是shared_ptr<>
实例的属性,因此shared_ptr<>
个对象的容器可能有一些具有不同删除器的对象。以下是Boost文档关于shared_ptr<>
删除者的说法:
自定义解除分配器允许工厂 函数返回
shared_ptr
将用户与其内存隔离开来 分配策略。自从 deallocator不属于该类型, 改变分配策略的确如此 不破坏源或二进制 兼容性,并不需要 客户端重新编译。例如,a “no-op”deallocator非常有用 静态地返回shared_ptr
分配对象和其他变体 允许shared_ptr
用作 另一个智能指针的包装器, 缓解互操作性。
如果您可以修改IFoo
以获得虚拟析构函数,那将是最干净的,因为您计划通过IFoo
引用或指针删除作为其子类的对象。但是,如果您遇到无法纠正的IFoo
,那么如果您想在容器中使用shared_ptr<IFoo>
,但指向Bar
,则可以创建{ {1}}具有执行向下转换为shared_ptr
的删除操作的实例然后执行删除操作。 Downcast被认为是不好的形式,但这种技术可能是你可以在绑定中使用的东西。