C ++类设计 - 如何在基类析构函数中清理

时间:2012-11-06 23:23:20

标签: c++ oop virtual feedback

我无法在框外思考以下问题。我有一个类层次结构:

[BaseClass] --> [Win32Class]

[BaseClass] --> [LinuxClass]

[BaseClass] --> [VxWorksClass]

实现类将调用API级函数。这些是在基类的纯虚函数内完成的。

现在,当用户创建,使用并完成对象时,他应该调用Done函数(来自基类),这将执行清理和资源取消分配。这种清理的一部分是调用许多API级函数 - 这些函数当然是基类中的纯虚函数,并在派生类中实现。到目前为止一切都很好。

这就是问题所在。如果用户没有显式调用Done,则由于资源未正确释放,将会出现各种内存泄漏。所以,我认为我可以轻松地从Done调用~BaseClass() - 在破坏时自动清理,我想。好吧,不是那么多。由于Done调用这些纯粹的虚拟内容,所以所有地狱都会崩溃。

有关如何重新设计以避免此问题的任何想法?

示例代码

class BaseClass{ 
  virtual ~BaseClass(){
    Done();
  }
  void Done(){
    // A bunch of OS-independent clean-up logic
    Cleanup();
    // some more OS-independent clean-up logic
  }
  virtual void Cleanup() = 0;
};
class Win32Class : public BaseClass{
  virtual void Cleanup(){
    // call some Win32-specific cleanup code
  }
};
class LinuxClass : public BaseClass{
  virtual void Cleanup(){
    // call some Linux-specific cleanup code
  }
};

==========================================
这是我的解决方案。使用包装类。不要在DoneWin32Class

的析构函数中致电BaseClass
class Win32Wrapper{
public:
  Win32Class* object_;
public:
  Win32Wrapper(){
    this->object_ = new Win32Class;
  }
  ~Win32Wrapper(){
    this->object_->Done();
    delete this->object_;
  }
};

==如何在析构函数中调用Pure Virtuals ==

class Base{
public:
  Base(){
  }
  virtual ~Base(){
    Done();
  }
  void Done(){
    Clean();
  }
  virtual void Clean() = 0;
};

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

用户认为该程序可以正常工作,因为编译器并没有抱怨Base::Done()中对PFV的调用。

3 个答案:

答案 0 :(得分:2)

您可以将清理代码放在派生的析构函数中:

struct Base
{
    virtual ~Base() { }

    void CleanUp() { /* ... */ }
};

struct Derived : Base
{
    virtual ~Derived()
    {
        CleanUp();
    }
};

如果需要,您甚至可以将对更多虚拟的调用放入非虚拟Base::CleanUp()函数中以允许特定于派生的行为(尽管通过您的描述听起来您不需要它)。 / p>

答案 1 :(得分:0)

我认为RAI​​I成语正是你要找的。

您可以在此处找到相当全面的说明:http://www.hackcraft.net/raii/

答案 2 :(得分:0)

您有两种选择。

  1. BaseClass的用户必须致电Done(),由于不这样做而导致的任何错误都是他的责任。
  2. 每个派生类执行其破坏者所需的任何清理。他们可以在清理中使用BaseClass函数,BaseClass函数甚至可以调用派生类重写的函数。