非虚拟析构子的双重继承(Y 形)

Double inheritance with non-virtual destirutor (Y-shaped)

我有 Y 型 class 层次结构:class C 继承自 A 和 B,class D 继承自 C。A 和 B 具有虚拟析构函数,而 C 的析构函数是不是虚拟的。我知道如果没有双重继承(比如没有 B),~C() 将是虚拟的。我的问题是双重继承会影响它吗?

class A { virtual ~A(); ...};
class B { virtual ~B(); ...};
class C : public A, public B { ~C(); ...};
class D : public C { virtual ~D(); ... };

我必须通过指向 C 的指针删除 class D 的实例。

C* c = new D;
delete c;

我怀疑在某些极端情况下 ~B() 未执行 - 这可能吗?它可以取决于优化级别吗?调用 'delete c' 的 .cc 文件中是否应存在 to D 的定义?

除了 ~B() 之外的所有析构函数都是 nop,class C 是空的 class:没有数据成员,没有函数,只有一个普通的构造函数和一个空的析构函数。我写了几个测试程序在所有情况下都执行了~B(),但我确定我没有尝试所有可能的组合。

C's destructor is not virtual.

是的。它有一个带有虚拟析构函数的基类,所以 C 的析构函数是隐式虚拟的。析构函数是否显式声明为虚拟无关紧要。 D.

的析构函数也是如此

I have to delete instances of class D through a pointer to C.

I suspect that there are some corner cases where ~B() is not executed - is it possible?

只要C的析构函数是virtual就没有问题。如果 C 的析构函数不是虚拟的,则通过指向 C 的指针删除派生对象将具有未定义的行为。

据我所知,析构函数链接与虚拟析构函数无关。只要调用了某个class的析构函数,它就会自动为你调用基础class的析构函数。

当您通过基 class.

的指针删除派生 class 实例时,Destructor 的虚拟性就会出现。

在您上面的示例中,假设 ~C 不是虚拟的(即您没有为任何析构函数声明虚拟),并且如果您要通过 C* 删除 D 实例,D 的析构函数可能已被遗漏,编译器将改为为您调用 ~C。如上所述,调用 ~C 将导致所有基 class 析构函数(~A & ~B)被自动调用。

但是,假设您已经在基础 class(A 等)中声明析构函数为虚拟,虚拟性将传播到所有派生的 classes 的析构函数。这意味着,即使您没有将 ~C 声明为虚拟,它实际上也是虚拟的。

C 析构函数是隐式虚拟的,因为它的至少一个基本析构函数是虚拟的。

因此,因为 C 析构函数是虚拟的,并且您通过指向 C 的指针进行删除,将调用 D 析构函数。

如果 AB 析构函数都不是虚拟的,那么删除 D 对象将是未定义的行为,但这里不是这种情况。

如果 class C 派生自 class(es),那么它知道如何销毁它的基础 classes。因此 B 析构函数将始终被调用(假设您删除最终对象或从析构函数显式或隐式虚拟的级别删除。

实际上,即使在未定义的情况下(只有 D 析构函数是虚拟的,对象通过 C 指针删除),B 析构函数可能会被调用,但 D 部分不会被正确销毁。 但是因为它是未定义的,所以你不能依赖它