基础和派生虚拟析构函数的影响

时间:2012-11-17 00:25:28

标签: c++ memory-leaks derived virtual-destructor

我对多个虚拟析构函数有了一些想法,特别是。阅读后阅读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;
}

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

2 个答案:

答案 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的原因很简单,这意味着对象大小总是增加一个字大小,这通常是不可接受的。