我能清楚地了解的大多数 OO 理论但很迷惑了我的一件事是虚析构函数。

我以为,调用析构函数总是获取无论是什么内容以及链中每个对象。

当您是以虚拟和为什么?

2009-01-20 12:58:21
问题评论:

看到这一点︰虚析构函数

每一个析构函数获取调用无论是什么内容。virtual可确保它在顶部而不是中间开始。

相关的问题︰时您不应使用虚析构函数?

许多年前我是 c + + 程序员,这是最常见的面试问题。

回答:

您可以删除指向基类的指针到派生类的实例时,虚析构函数很有用︰

class Base 
{
    // some virtual methods
};

class Derived : public Base
{
    ~Derived()
    {
        // Do some important cleanup
    }
}

在这里,您会注意到我没有声明基类的析构函数是虚。现在,让我们看看下面的代码段︰

Base *b = new Derived();
// use b
delete b; // Here's the problem!

由于基类的析构函数不是虚拟,而bBase*指向Derived对象,delete b具有未定义的行为在大多数的实现中,对析构函数的调用将解决像任何非虚拟代码,意味着将调用基类的析构函数但不是是派生类,从而导致资源泄漏。

总而言之,始终使基类的析构函数虚拟时他们正在打算以多态形式处理。

如果您想要防止通过基类指针的实例删除,您可以使基类 destuctor 受保护和非虚拟的;这样,编译器不允许您删除基类指针上的调用。

您可以了解有关 virtuality 虚拟基类析构函数,本文从等 Sutter详细信息.

这不能解释一下为什么我会有使用工厂的大规模泄漏我做在前。所有现在是有意义。谢谢

这也有效,如果鼠标指针是 void * 吗?

不,它不是。Void 指针不了解析构函数。

不,它不会起作用具有 void *。编译器一无所知什么 void * 点处。它知道的只是它是一个内存位置。您需要强制转换指针指向的类型通知编译器是什么存在。

嗯,这是一个坏的例子,因为没有数据的成员。如果BaseDerived具有自动存储的所有变量?ie 没有"特殊"或其他自定义代码的析构函数中执行。那么它确定来关闭所有写入任何析构函数?或者,将派生的类有内存泄漏?

声明虚拟多态的基类中的析构函数。这是 Scott Meyers有效的 c + +项目第 7。Meyers 转到总结,如果类具有任何虚函数,它应具有虚拟析构函数,类没有设计为基类,这些类或不设计用于以多态形式应该虚析构函数声明。

+"如果类具有任何虚函数,它应具有虚拟析构函数,并且该类没有设计为基类,这些类或不设计用于以多态形式不应声明虚拟析构函数。": 有的意义中断此规则的情况下?如果不是,它有意义让编译器检查此条件和问题错误是不满足吗?

我不知道该规则的例外情况的 @Giorgio。但我不评价自己作为一名 c + + 专家,因此可能需要将此作为单独问题。编译器警告 (或静态分析工具的警告) 意义给我。

类可以用于不删除通过某些类型的指针,但仍有虚函数的典型示例是一个回调接口。一个不会删除通过回调接口指针他实现为仅用于订阅,但没有虚函数。

@dascandy 完全-,或所有许多其他情况下,我们使用多态行为,但不能完成通过指针-如带有指针仅用作观察路由维护自动或静态持续对象的存储管理。不需要/目的在任何这种情况下实施虚拟析构函数。因为我们只报价此处的人,我更喜欢从上面 Sutter:"准则 #4︰ 基类析构函数应该是公共和虚拟或受保护和非虚拟。"后者将确保任何人无意尝试删除通过基指针显示其方法的误差

虚拟的构造函数是不可能,但可以虚拟析构函数。让我们尝试...

#include <iostream>
using namespace std;
class base
{

public:
    base(){cout<<"Base Constructor Called
";}
    ~base(){cout<<"Base Destructor called
";}

};
class derived1:public base
{

public:
    derived1(){cout<<"Derived constructor called
";}
    ~derived1(){cout<<"Derived destructor called
";}

};
int main()
{

    base* b;
    b=new derived1;
    delete b;

}

上述代码将输出下面...

Base Constructor Called
Derived constructor called
Base Destructor called

派生的对象的构造遵循的构造规则,但当我们删除"b"指针 (基指针) 我们发现只有基析构函数被调用。但这必须不会发生了。要做适当的事我们必须使虚拟基类的析构函数。现在请参阅下面发生什么...

#include <iostream>
using namespace std;
class base
{

public:
    base(){cout<<"Base Constructor Called
";}
    virtual ~base(){cout<<"Base Destructor called
";}

};
class derived1:public base
{

public:
    derived1(){cout<<"Derived constructor called
";}
    ~derived1(){cout<<"Derived destructor called
";}

};
int main()
{

    base* b;
    b=new derived1;
    delete b;

}

更改为以下输出

Base Constructor Called
Derived constructor called
Derived destructor called
Base Destructor called

因此基指针 (这在派生的对象上执行分配 !) 销毁按照破坏规则,即首先派生然后基。另一方面对于构造函数在一点也不像虚拟的构造函数。谢谢

"虚拟的构造函数不是可能的",意味着不需要您自己来写入虚拟的构造函数。派生的对象的构造必须遵循从建筑链派生为基础。因此不需要为您的构造函数编写 virtual 关键字。谢谢

@Murkantilism,"虚拟的构造函数不能"也是确实如此。构造函数不能标记为虚拟。

@cmeub,但成语来实现想从虚拟的构造函数。请参见parashift.com/c++-faq-lite/virtual-ctors.html

另外请注意,删除基类指针没有虚析构函数时将导致未定义的行为我只是在最近学到的某些内容︰

http://stackoverflow.com/questions/408196/how-should-overriding-delete-in-c-behave

我一直多年使用 c + + 和我仍然管理挂起自己。

我一看这个问题您,看到您已经声明为虚基类析构函数。因此 does"没有虚析构函数将导致未定义的行为时,则删除基类指针"保持您这个问题有效吗?以来,在这个问题中,当调用 delete,派生的类 (由其 new 运算符创建) 兼容版本首先检查。它找到一个,因为它将被调用。因此,您认为会好一些,为"时没有的析构函数将导致未定义行为,则删除基类指针"说不?

这是很多同样的事情。默认构造函数不是虚拟的。

多态类时,请析构函数虚拟。

内容来源于Stack Overflow When to use virtual destructors?
请输入您的翻译

When to use virtual destructors?

确认取消