如果在派生类中定义了虚拟析构函数,但不是层次结构的顶部,该怎么办?C++
What if the virtual destructor defined in derived class, but not the top of hierarchy? C++
我想知道定义一个没有虚拟析构函数的基类,并使用虚拟析构函数定义继承的类是否正确?如果我这样做,实际上会发生什么?
如果你delete p
p
是X*
类型,但实际上指向一个派生自X
的Y
,除非X
有一个virtual
析构函数,否则你有未定义的行为。如果Y
的析构函数是virtual
但X
析构函数不是,它什么都不会改变。
如果你打算这样做
delete pB;
其中pB
是类型Base*
,pB
可能指向类型Derived
的对象,其中Derived
是(直接或间接(派生的Base
类,那么,
必须为 Base
声明虚拟析构函数。
只要您不打算这样做,Base
就可以没有虚拟析构函数。
特别是,如果您有具有非虚拟析构函数的类B1
,以及从具有虚拟析构函数的B1
派生的类B2
,以及派生自B2
的类D
,则可以使用指向B2
的指针来删除类型D
的对象,因为B2
具有虚拟析构函数...但是使用指向B1
的指针来删除类型为 B2
或 D
的对象是未定义的行为,因为B1
没有虚拟析构函数。
无论如何,函数在派生类中virtual
,而在基类中不virtual
的想法是令人困惑的,所以除非我有很好的理由,否则我不会这样做。
虚拟析构函数允许您仅使用指向基类的指针来调用正确的析构函数。如果没有虚拟析构函数,delete base_ptr
只会调用基类的析构函数(或调用未定义的行为(。但是,析构函数调用是否动态调度仅取决于基类,因此,如果基类不使其成为虚拟的,那么如果某些派生类添加了虚拟析构函数,这不会突然变成虚拟调度!
笔记:
- 如果基类
- 没有虚拟析构函数,请不要将其用作基类。最多使用私有/受保护的继承,但不使用公共继承。
- 如果您编写基类但不想要求虚拟析构函数(在编写 mixins 时很常见(,则可以改为保护析构函数。
这两个建议可防止意外调用非虚拟基类析构函数。
如果您不在父类中声明 virtual,它将不起作用。
[~/cpp/VirtualDestructor]$ cat main.cpp
class A
{
public:
~A() {}
};
class B : public A
{
public:
B() : val(new char) {}
virtual ~B() { delete val; }
private:
char* val;
};
int main()
{
A* x = new B;
delete x;
}
[~/cpp/VirtualDestructor]$ valgrind ./run
==20382== Memcheck, a memory error detector
==20382== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==20382== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==20382== Command: ./run
==20382==
==20382==
==20382== HEAP SUMMARY:
==20382== in use at exit: 1 bytes in 1 blocks
==20382== total heap usage: 2 allocs, 1 frees, 17 bytes allocated
==20382==
==20382== LEAK SUMMARY:
==20382== definitely lost: 1 bytes in 1 blocks
==20382== indirectly lost: 0 bytes in 0 blocks
==20382== possibly lost: 0 bytes in 0 blocks
==20382== still reachable: 0 bytes in 0 blocks
==20382== suppressed: 0 bytes in 0 blocks
==20382== Rerun with --leak-check=full to see details of leaked memory
==20382==
==20382== For counts of detected and suppressed errors, rerun with: -v
==20382== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
[~/cpp/VirtualDestructor]$
B
实例由A*
指针指向。然后当你delete
它时。如果A
的析构函数不是virtual
,它将通过A
的析构函数
- 如何重构类层次结构以避免菱形问题
- C++ 中模板化类型的类层次结构
- 为什么不同类型层次结构的指针之间的dynamic_cast定义得很好?
- 继承层次结构并将元素添加到向量
- C++ 类层次结构中的"对齐"是什么意思?
- 相同的层次结构,访问基类的受保护成员时的行为不同
- 类层次结构中的运算符重载
- 如何在层次结构中实现运算符使用?
- 反向层次结构中的可变参数模板参数
- 如何在继承层次结构中调用具有默认参数的构造函数?
- C++ 提升 - 包含类层次结构对象的类的序列化
- 在C++继承层次结构时提取实现者
- 在C++中将类实例添加到对象层次结构中的问题
- 确定大层次结构中基本指针的实际类型,无需dynamic_cast
- 在继承层次结构中复制和移动
- 模板冲突的类型-但类型应该是相同的cfr类层次结构
- 删除父/子窗口层次结构的最佳方法
- 是否可以使一个类成为两个不同层次结构的子类?
- OOP - 类层次结构的顶部称为什么
- 如果在派生类中定义了虚拟析构函数,但不是层次结构的顶部,该怎么办?C++