开始在现有代码库上使用PC-Lint(恐惧和恐惧)。
它抱怨的一件事是:
class IBatch
{
public:
virtual void StartBatch() =0;
virtual int CommitBatch() =0;
};
当另一个类派生于此时,将其用作接口
base class 'IBatch' has no destructor
所以,问题是:当您创建如上所述的 Interface 类时,您是否始终包含虚拟析构函数?为什么? (是样式还是编码错误?)
编辑:应该说我不希望或希望IBatch的用户破坏,他们只是一个服务的消费者,通过这个接口到一些外部实现类(如果那样的话)有所作为)答案 0 :(得分:28)
基类析构函数应该是public和virtual,或者是protected和nonvirtual。
答案 1 :(得分:8)
编码错误 - 如果通过指向基类的指针调用,派生类的析构函数将永远不会被调用。
实现IBatch
并通过指向基类的指针(指向IBatch
的指针)引用派生类,并在指向基类的指针上调用delete
最终导致内存泄漏,因为派生类的析构函数永远不会被调用。
基本规则是当一个类至少有一个virtual
方法需要virtual
析构函数时。
class IBatch
{
public:
virtual void f() = 0;
};
class A : public IBatch
{
public:
void f() {}
~A() {}
};
IBatch * a = new A();
a->f(); // calls A::f()
delete a; // calls IBatch::~IBatch() not A::~A()
答案 2 :(得分:7)
如果有虚函数,则需要有一个虚析构函数。总是。它只是一个接口类并不重要 - 它仍然需要虚拟析构函数。
要么是,要么需要protected
非虚拟析构函数。但是你不能使用界面指针删除对象。
答案 3 :(得分:4)
具有虚函数但没有虚拟析构函数的类是可疑的,并且很可能是错误的:查看更好更准确的解释here。
答案 4 :(得分:2)
所以,问题是:何时创建 像上面这样的接口类,做 你总是包括一个虚拟的 析构函数?为什么? (是风格还是风格 编码错误?)
这真的取决于它。如果您曾在IBatch指针上调用delete,那么它可能无法满足您的期望。当然,如果您有虚拟Init / Shutdown或AddRef / Releases之类的东西,那么它并不是真正的问题。
答案 5 :(得分:0)
编译器放置非虚拟的默认析构函数,这意味着指向虚拟基类的指针上的“删除”将成功导致内存泄漏。因此,它是一个实现缺陷,无论是样式还是编码错误。