6

我对多个虚拟析构函数有了一些重新考虑,尤其是。在阅读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;
}

这会按我的预期工作,没有内存泄漏吗?

4

2 回答 2

5

首先,如果你创建了基类 destructor ,那么无论你声明它们为与否virtual,所有派生类都会自动获得一个析构函数。这对于匹配签名通常是正确的:如果基类具有与派生类中的函数具有相同签名的函数,则派生类中的函数是 an和 is (尽管在 C++ 2011 中,您可以使用关键字防止进一步覆盖在这种情况下,另一个覆盖会产生错误)。virtualvirtualvirtualoverridevirtualfinal

也就是说,析构函数是特殊的:当你创建一个析构函数时virtual,即使有另一个覆盖的析构函数,它仍然会被调用!析构函数存在的唯一影响virtual是,如果您delete的对象使用指向基类的指针,而该对象实际上恰好是派生类型,则会发生什么:如果析构函数不是virtual,您将获得未定义的行为,而正确的事情发生析构函数是virtual. 例如:

class not_a_base {};
class bad_idea: public not_a_base {};

class a_base { public: virtual ~a_base() {} };
class ok: public a_base {};

int main() {
    a_base* ab = new ok;
    delete ab; // <---- all is good here!

    not_a_base* nab = new bad_idea;
    delete nab; // <---- results in undefined behavior
}

默认情况下不使用析构函数的原因virtual很简单,这意味着对象大小总是增加一个字长,这通常是不可接受的。

于 2012-11-17T00:48:45.713 回答
4

Base::_logger那么 是一个不同的变量Derived::_logger。所以你应该Derived::_logger在 Derived 的 dctor 中删除,否则你会泄漏内存。

请注意,这与它是私有的无关。考虑这个示例程序:

#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将在它们中被删除。

于 2012-11-17T00:44:52.920 回答