非虚拟析构子的双重继承(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
析构函数。
如果 A
或 B
析构函数都不是虚拟的,那么删除 D
对象将是未定义的行为,但这里不是这种情况。
如果 class C
派生自 class(es),那么它知道如何销毁它的基础 classes。因此 B
析构函数将始终被调用(假设您删除最终对象或从析构函数显式或隐式虚拟的级别删除。
实际上,即使在未定义的情况下(只有 D
析构函数是虚拟的,对象通过 C
指针删除),B
析构函数可能会被调用,但 D
部分不会被正确销毁。 但是因为它是未定义的,所以你不能依赖它。
我有 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
析构函数。
如果 A
或 B
析构函数都不是虚拟的,那么删除 D
对象将是未定义的行为,但这里不是这种情况。
如果 class C
派生自 class(es),那么它知道如何销毁它的基础 classes。因此 B
析构函数将始终被调用(假设您删除最终对象或从析构函数显式或隐式虚拟的级别删除。
实际上,即使在未定义的情况下(只有 D
析构函数是虚拟的,对象通过 C
指针删除),B
析构函数可能会被调用,但 D
部分不会被正确销毁。 但是因为它是未定义的,所以你不能依赖它。