4
class A {
public:
  ~A() { release(); }
  virtual release() { cout << "~A"; } 
}

class B : public A {
  release() { cout << "~B"; }
}

当我删除 B 时,只调用了 A 类的 release() 方法。

我想要实现的是对于每个子对象,当它被删除时,我想调用在每个子类中被覆盖的 release 方法,而不需要为每个子对象手动指定析构函数来调用 release(我很懒)。这实际上不可能以这种方式或任何其他方式实现吗?

4

3 回答 3

7

析构函数的执行顺序与构造函数的相反,所以当Ain aB被销毁时,它的B组件已经被销毁并且不再存在。在被破坏的对象上调用方法会产生未定义的行为,这就是为什么对虚拟方法的调用总是解析为构造函数析构函数中的当前类类型。

所以基本上不,你不能这样做。你必须把它们都写下来。

于 2012-12-22T17:45:08.657 回答
3

不要从析构函数或构造函数调用虚方法——它们不会做你期望它们做的事情。

放弃懒惰并编写析构函数。

于 2012-12-22T17:45:25.913 回答
3

此类问题的解决方案是预销毁阶段,您可以在其中手动控制销毁的发生方式。

pImpl使用该模式实现您的对象。当包装对象被销毁时,pImpl在销毁它之前通知它将被销毁。

pImpl可以有一个virtual PreDestroyable允许子方法注册PreDestruction回调的基类,您可以在此预销毁阶段调用该回调。

class Destroyable {
protected:
  Destroyable() {}; // must be empty
  virtual ~Destroyable() { Assert(PreDestroyers.empty()); };
  void RegisterPreDestroy( std::function<void()> const& func ) { PreDestroyers.push_back(func) );
private:
  std::vector<std::function<void()>> PreDestroyers;
public:
  // reverse order, reentrant:
  void PrepareToDie() {
    while (!PreDestroyers.empty()) {
      auto f = PreDestroyers.back();
      PreDestroyers.pop_back();
      f();
    }        
  }
};

// handles registration:
template<typename T>
class HasPreDestroyCode: public virtual Destroyable {
  // TODO: usual CRTP static or dynamic checks:
  T* self() { return static_cast<T*>(this); }
  T const* self() const { return static_cast<T*>(this); }
  HasPreDestroyCode() {
    RegisterPreDestroy( [&]() { self()->PreDestroy(); } );
  }
  HasPreDestroyCode( HasPreDestroyCode const& other ) {
    RegisterPreDestroy( [&]() { self()->PreDestroy(); } );
  }
  HasPreDestroyCode( HasPreDestroyCode const& other ) {
    RegisterPreDestroy( [&]() { self()->PreDestroy(); } );
  }
private:
  HasPreDestroyCode& operator=( HasPreDestroyCode const& other ) = delete;
};

class Test: HasPreDestroyCode<Test> {
public:
  void PreDestroy() {}
};

我上次在 C++11 之前写了这些东西,所以我还没有弄清楚如何处理构建它的移动。并且这一切都是在运行时完成的,而可能用更少的运行时数据来做类似上面的事情。类似于层次结构中包含预销毁代码的类型列表之类的东西?

于 2012-12-22T18:18:04.047 回答