我对大多数OOP理论都有很好的理解,但最让我困惑的是虚拟析构函数。
我以为析构函数总是被调用,不管是什么,也不管是链中的每个对象。
你打算什么时候让它们虚拟化?为什么?
我对大多数OOP理论都有很好的理解,但最让我困惑的是虚拟析构函数。
我以为析构函数总是被调用,不管是什么,也不管是链中的每个对象。
你打算什么时候让它们虚拟化?为什么?
当前回答
简单地说,当您删除指向派生类对象的基类指针时,虚拟析构函数将以正确的顺序析构函数资源。
#include<iostream>
using namespace std;
class B{
public:
B(){
cout<<"B()\n";
}
virtual ~B(){
cout<<"~B()\n";
}
};
class D: public B{
public:
D(){
cout<<"D()\n";
}
~D(){
cout<<"~D()\n";
}
};
int main(){
B *b = new D();
delete b;
return 0;
}
OUTPUT:
B()
D()
~D()
~B()
==============
If you don't give ~B() as virtual. then output would be
B()
D()
~B()
where destruction of ~D() is not done which leads to leak
其他回答
如果使用shared_ptr(仅shared_ptl,而不是unique_ptr),则不必将基类析构函数设为虚拟:
#include <iostream>
#include <memory>
using namespace std;
class Base
{
public:
Base(){
cout << "Base Constructor Called\n";
}
~Base(){ // not virtual
cout << "Base Destructor called\n";
}
};
class Derived: public Base
{
public:
Derived(){
cout << "Derived constructor called\n";
}
~Derived(){
cout << "Derived destructor called\n";
}
};
int main()
{
shared_ptr<Base> b(new Derived());
}
输出:
Base Constructor Called
Derived constructor called
Derived destructor called
Base Destructor called
我建议这样做:如果类或结构不是最终的,那么应该为其定义虚拟析构函数。
我知道这看起来像是一种过度警惕的过度杀戮,成为一种经验法则。但是,这是确保从类派生的人在使用基指针删除时不会使用UB的唯一方法。
Scott Meyers在下面引用的有效C++中的建议很好,但不足以确定。
如果一个类有任何虚函数,它应该有一个虚函数析构函数,并且类是否设计为基类设计用于多态性的不应声明虚拟析构函数。
例如,在下面的程序中,基类B没有任何虚拟函数,因此根据Meyer的说法,您不需要编写虚拟析构函数。然而,如果您没有以下UB:
#include <iostream>
struct A
{
~A()
{
std::cout << "A::~A()" << std::endl;
}
};
struct B
{
};
struct C : public B
{
A a;
};
int main(int argc, char *argv[])
{
B *b = new C;
delete b; // UB, and won't print "A::~A()"
return 0;
}
还要注意,在没有虚拟析构函数时删除基类指针将导致未定义的行为。我最近学到的东西:
C++中重写删除应该如何操作?
我已经使用C++多年了,但我还是设法自杀了。
在多态基类中声明虚拟的析构函数。这是Scott Meyers的有效C++中的第7项。Meyers接着总结道,如果一个类有任何虚拟函数,那么它应该有一个虚拟析构函数,而不是设计为基类或不是设计为多态使用的类不应该声明虚拟析构器。
只要类是多态的,就将析构函数设为虚拟。