我无法在框外思考以下问题。我有一个类层次结构:
[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
}
};
==========================================
这是我的解决方案。使用包装类。不要在Done
或Win32Class
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的调用。
答案 0 :(得分:2)
您可以将清理代码放在派生的析构函数中:
struct Base
{
virtual ~Base() { }
void CleanUp() { /* ... */ }
};
struct Derived : Base
{
virtual ~Derived()
{
CleanUp();
}
};
如果需要,您甚至可以将对更多虚拟的调用放入非虚拟Base::CleanUp()
函数中以允许特定于派生的行为(尽管通过您的描述听起来您不需要它)。 / p>
答案 1 :(得分:0)
我认为RAII成语正是你要找的。 p>
您可以在此处找到相当全面的说明:http://www.hackcraft.net/raii/
答案 2 :(得分:0)
您有两种选择。
BaseClass
的用户必须致电Done()
,由于不这样做而导致的任何错误都是他的责任。BaseClass
函数,BaseClass
函数甚至可以调用派生类重写的函数。