class A{public:A() {}virtual void foo(){cout << "This is A." << endl;}};
class B : public A{public:B() {}void foo(){cout << "This is B." << endl;}};
int main(int argc, char* argv[]){A *a = new B();a->foo();if(a != NULL)delete a;return 0;}
// library.hpp
struct Base {
virtual void f() = 0;
protected:
~Base() = default;
};
void CallsF(Base& base);
// CallsF is not going to own "base" (i.e. call "delete &base;").
// It will only call Base::f() so it doesn't need to access Base::~Base.
//-------------------
// application.cpp
struct Derived : Base {
void f() override { ... }
};
int main() {
Derived derived;
CallsF(derived);
// No need for virtual destructor here as well.
}
#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
如果运行上面的代码,就会清楚地看到问题发生的时间。当基类(/struct)的 this 指针与派生类(/struct)的 this 指针不同时,就会遇到这个问题。在上面的示例中,struct a 和 b 没有 vtables。结构 c 和 d 都有 vtables。因此,指向 c 或 d 对象实例的 a 或 b 指针将被修复为 vtable。如果传递这个 a 或 b 指针来删除它,它将崩溃,因为地址对堆的空闲例程来说是无效的。
在从 Fruit 对象集合中删除时,
~ Apple ()和 ~ Orange ()不能被调用,除非 ~ Water ()是虚拟的。
举个正确的例子:
#include <iostream>
using namespace std;
struct Fruit { // good
virtual ~Fruit() { cout << "peel or core should have been tossed" << endl; }
};
struct Apple: Fruit { virtual ~Apple() {cout << "toss core" << endl; } };
struct Orange: Fruit { virtual ~Orange() {cout << "toss peel" << endl; } };
int main() {
Fruit *basket[]={ new Apple(), new Orange() };
for (auto fruit: basket) delete fruit;
};
输出正常
toss core
peel or core should have been tossed
toss peel
peel or core should have been tossed
错误的例子:
#include <iostream>
using namespace std;
struct Fruit { // bad
~Fruit() { cout << "peel or core should have been tossed" << endl; }
};
struct Apple: Fruit { virtual ~Apple() {cout << "toss core" << endl; } };
struct Orange: Fruit { virtual ~Orange() {cout << "toss peel" << endl; } };
int main() {
Fruit *basket[]={ new Apple(), new Orange() };
for (auto fruit: basket) delete fruit;
};
输出不良
peel or core should have been tossed
peel or core should have been tossed
例如,在下面的程序中,基类 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;
}