2013-04-08 85 views
1

看一看C++语言标准,有没有什么办法可以调用派生类的析构函数,而无需调用基类的析构函数?只有调用类的调用析构函数

因此,对于类

class Base { public: virtual ~Base() {} }; 
class Derived : public Base { public: ~Derived();}; 

如果将是可能的写代码等

Base *basePtr = new Derived(); 
//do something with basePtr 

// Now somehow destroy Derived while keeping Base - call ~Derived() only, 
// line below however will call both ~Derived() and ~Base() - how it can be done? 
dynamic_cast<Derived*>(basePtr)->~Derived(); 

于是,经过上述basePtr代码的执行将仅指向的基本对象,一样,如果它是由

创建
Base *basePtr = new Base(); 

加上对操作引起的Base对象的任何修改basePtr之间调用新的Derived()和销毁派生类?

或者,这是禁止的,这是不可能的吗?

+0

@NPE如果这是可能的,该怎么做?用例的动机是由http://stackoverflow.com/questions/15843549/cast-one-derrived-class-to-another-without-changing-base-class,我从现在开始单独询问这部分好奇,如果它在所有理论上是可能的,以及如何做到这一点... – 2013-04-08 15:56:31

+0

其实,我没有注意到*,而保留'基地'*位。我撤回了我以前的评论。 – NPE 2013-04-08 15:58:34

+0

听起来像是一个XY问题... – Griwes 2013-04-08 16:24:57

回答

0

正如你提出的问题,不可能实现你所要求的。除非你有内存泄漏,否则显式调用析构函数的唯一情况不会导致未定义的行为,如果该对象是通过放置new创建的。即使这样,调用析构函数也会自动调用每个成员和基类的析构函数。

这是应该的。否则,编写正确的容器类或内存管理器将非常困难。

该标准规定,对象的生命周期一旦进入析构函数就会结束。它不会成为基类对象。它完全不再是一个对象。而且,如果情况并非如此,那么在这样一个窍门之后,从多个基地派生的一个阶级的地位会是什么?

最终,这种功能的“需求”是设计不好的标志。我想你的用例更可能需要组合。看看你是否无法用一个新的类来解决这个问题,该类包含一个当前基类的实例和一个可选的可替换的组件(一个智能指针),一些虚拟类可以作为接口和新的公共基础你当前的派生类。这样你可以删除(和破坏)这些子对象而不用触及底座。

+0

你可以明确地调用析构函数,而不需要新放置,因为析构函数从不被调用,也就是说,内存几乎肯定会泄漏。 – Griwes 2013-04-08 16:31:47

+0

@Griwes良好的捕获,我完全忘记了内存泄漏。我相应地修改了我的答案。 – Agentlien 2013-04-08 16:43:13

0

析构函数以相反的构造顺序自动调用。我不相信这有什么办法。

0

除非派生类与您的基类无关,否则这是不可能的。

以自动方式调用析构函数。显式调用析构函数可能导致未定义的行为。

2

不,这是不可能的。该标准要求破坏Derived对象会破坏整个对象,包括Base子对象。根据C++对对象生命周期的理解,其他任何东西都不会成为破坏。

取决于你想要达到的目标,考虑到基本复制出来的衍生第一

std::unique_ptr<Base> basePtr(new Derived()); 
//do something with basePtr 

basePtr.swap(std::unique_ptr<Base> (new Base(*basePtr))); //splice the Base part out of the derived object 

//basePtr now points to the spliced Base object. 

另一种办法是持有派生有一个boost::optional(或只是一个平普尔)的其他成员并重置它以获得仍然具有其基类部分的“剥离”派生对象。但这不会影响虚拟功能调度。