为什么删除没有虚拟 dtor 的 class 是可以的,如果它继承了带有虚拟 dtor 的 class
Why delete a class without virtual dtor is OK if it inherits a class with virtual dtor
考虑下面的代码
#include <cstdio>
#include <memory>
struct Base1
{
Base1() = default;
virtual ~Base1() = default;
//~Base1() = default;
};
struct Base2 : public Base1
{
Base2()
{
printf("%s:%d:%s\n", __FILE__, __LINE__, __func__);
}
~Base2() // non-virtual destructor
{
printf("%s:%d:%s\n", __FILE__, __LINE__, __func__);
}
};
struct Derive : public Base2
{
Derive()
{
printf("%s:%d:%s\n", __FILE__, __LINE__, __func__);
}
~Derive()
{
printf("%s:%d:%s\n", __FILE__, __LINE__, __func__);
}
};
int main()
{
std::unique_ptr<Base2> d = std::make_unique<Derive>();
return 0;
}
classBase2
没有虚析构函数,但是继承了Base1
有虚析构函数
代码 std::unique_ptr<Base2> d = std::make_unique<Derive>();
正在尝试删除类型为 Derive
的对象上的 Base2
,我原以为只会调用 Base2
的 dtor,但不会调用Derive
.
但实际上它工作正常:
main.cpp:15:Base2
main.cpp:27:Derive
main.cpp:31:~Derive
main.cpp:19:~Base2
所以看起来只要"real"基础class(这里是Base1
)有虚拟dtor,所有继承的class都不需要有虚拟dtor,是吗?
如果有,请问哪里可以找到相关的文档?
因为如果它继承自一个带有虚析构函数的class,那么它就有一个虚析构函数,即使你不必明确地将它标记为virtual
。
~Base2() // actually a virtual destructor
注意,如果你想确保~Base2()
是独立于~Base1()
的虚拟,那么你应该将它标记为virtual
。但通常你想要做的是确保 Base1()
实际上是虚拟的。这可以通过使用 override
说明符来实现:
~Base2() override; // fail to compile if ~Base1() is not virtual
是的,如果 class 有一个基础 class,其 destructor 被声明为 virtual
,它的析构函数也将是 virtual
;无论是否明确声明为 virtual
。
Even though destructors are not inherited, if a base class declares
its destructor virtual, the derived destructor always overrides it.
This makes it possible to delete dynamically allocated objects of
polymorphic type through pointers to base.
class Base {
public:
virtual ~Base() { /* releases Base's resources */ }
};
class Derived : public Base {
~Derived() { /* releases Derived's resources */ }
};
int main()
{
Base* b = new Derived;
delete b; // Makes a virtual function call to Base::~Base()
// since it is virtual, it calls Derived::~Derived() which can
// release resources of the derived class, and then calls
// Base::~Base() following the usual order of destruction
}
根据标准,[class.dtor]/13
(强调我的)
A prospective destructor can be declared virtual ([class.virtual]) or
pure virtual ([class.abstract]). If the destructor of a class is
virtual and any objects of that class or any derived class are created
in the program, the destructor shall be defined. If a class has a base
class with a virtual destructor, its destructor (whether user- or
implicitly-declared) is virtual.
考虑下面的代码
#include <cstdio>
#include <memory>
struct Base1
{
Base1() = default;
virtual ~Base1() = default;
//~Base1() = default;
};
struct Base2 : public Base1
{
Base2()
{
printf("%s:%d:%s\n", __FILE__, __LINE__, __func__);
}
~Base2() // non-virtual destructor
{
printf("%s:%d:%s\n", __FILE__, __LINE__, __func__);
}
};
struct Derive : public Base2
{
Derive()
{
printf("%s:%d:%s\n", __FILE__, __LINE__, __func__);
}
~Derive()
{
printf("%s:%d:%s\n", __FILE__, __LINE__, __func__);
}
};
int main()
{
std::unique_ptr<Base2> d = std::make_unique<Derive>();
return 0;
}
classBase2
没有虚析构函数,但是继承了Base1
有虚析构函数
代码 std::unique_ptr<Base2> d = std::make_unique<Derive>();
正在尝试删除类型为 Derive
的对象上的 Base2
,我原以为只会调用 Base2
的 dtor,但不会调用Derive
.
但实际上它工作正常:
main.cpp:15:Base2
main.cpp:27:Derive
main.cpp:31:~Derive
main.cpp:19:~Base2
所以看起来只要"real"基础class(这里是Base1
)有虚拟dtor,所有继承的class都不需要有虚拟dtor,是吗?
如果有,请问哪里可以找到相关的文档?
因为如果它继承自一个带有虚析构函数的class,那么它就有一个虚析构函数,即使你不必明确地将它标记为virtual
。
~Base2() // actually a virtual destructor
注意,如果你想确保~Base2()
是独立于~Base1()
的虚拟,那么你应该将它标记为virtual
。但通常你想要做的是确保 Base1()
实际上是虚拟的。这可以通过使用 override
说明符来实现:
~Base2() override; // fail to compile if ~Base1() is not virtual
是的,如果 class 有一个基础 class,其 destructor 被声明为 virtual
,它的析构函数也将是 virtual
;无论是否明确声明为 virtual
。
Even though destructors are not inherited, if a base class declares its destructor virtual, the derived destructor always overrides it. This makes it possible to delete dynamically allocated objects of polymorphic type through pointers to base.
class Base { public: virtual ~Base() { /* releases Base's resources */ } }; class Derived : public Base { ~Derived() { /* releases Derived's resources */ } }; int main() { Base* b = new Derived; delete b; // Makes a virtual function call to Base::~Base() // since it is virtual, it calls Derived::~Derived() which can // release resources of the derived class, and then calls // Base::~Base() following the usual order of destruction }
根据标准,[class.dtor]/13
(强调我的)
A prospective destructor can be declared virtual ([class.virtual]) or pure virtual ([class.abstract]). If the destructor of a class is virtual and any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.