我对多个虚拟析构函数有了一些想法,特别是。阅读后阅读http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx。
假设我有
class Base
{
public:
Base();
virtual ~Base();
private:
Logger* _logger;
};
//and
class Derived : public Base{
public:
Derived();
virtual ~Derived();
private:
Logger* _logger;
};
在cpp文件中,在每个析构函数中我删除了相应的_logger
指针
Base::~Base(){ //base.cpp
delete _logger;
}
Derived::~Derived(){ //derived.cpp
delete _logger;
}
这会像我预期的那样工作,没有内存泄漏吗?
答案 0 :(得分:4)
Base::_logger
是一个与Derived::_logger
不同的变量。所以你应该在Derived的dctor中删除Derived::_logger
,否则你会泄漏内存。
请注意,这与私有无关。考虑这个示例程序:
#include <iostream>
class A {
public:
bool foo;
};
class B: public A {
public:
bool foo;
};
int main()
{
B b;
std::cout << &b.B::foo << ' ' << &b.A::foo << '\n';
}
地址不同。这意味着它们是不同的变量,即使它们具有相同的名称。这是可能的,因为每个类都引入了自己的命名空间,因此名称不会真正发生冲突。第一个是A :: foo,另一个是B :: foo。
由于你的析构函数是虚拟的,因此两者都会被调用,并且两者都将删除正确的_logger
。
答案 1 :(得分:4)
首先,如果你创建基类析构函数virtual
,如果你将它们声明为virtual
,所有派生类将自动获得virtual
析构函数。这对于匹配签名通常是正确的:如果基类具有与派生类中的函数具有相同签名的virtual
函数,则派生类中的函数是override
并且是{{1 (尽管在C ++ 2011中,您可以使用virtual
关键字阻止进一步覆盖,在这种情况下,另一个覆盖会产生错误。)
也就是说,析构函数是特殊的:当你创建一个析构函数final
时,即使有另一个重写的析构函数,它仍然会被调用!析构函数virtual
的唯一影响是当对象实际恰好是派生类型时使用指向基类的指针virtual
时发生的情况:如果析构函数不是{ {1}}如果析构函数为delete
,则会出现未定义的行为,而正确的事情会发生。例如:
virtual
默认情况下析构函数不是virtual
的原因很简单,这意味着对象大小总是增加一个字大小,这通常是不可接受的。