File tree Expand file tree Collapse file tree 2 files changed +5
-8
lines changed Expand file tree Collapse file tree 2 files changed +5
-8
lines changed Original file line number Diff line number Diff line change @@ -404,9 +404,9 @@ MyDerived (0x0x6677f70) 0 nearly-empty
404
404
## 虚基类的析构函数
405
405
通过上面的打印信息发现一个细节,MyDerived明明没有定义析构函数,但还是帮我们生成了虚析构函数,而且打印位置还在` dfunc1 ` 的前面。说明这个析构函数是从基类里面来的,当基类虚函数表复制过来的时候,发现有析构函数,就自动将其替换为了派生类的析构函数。
406
406
407
- 这可能也与虚基类的析构函数必须是虚函数有关,也与虚函数在机器码中的调用方式有关。虚函数调用被编译为机器码时,是通过对象的地址偏移调用的。当我们有一个基类类型的多态对象被delete时,如果你没有把基类的析构函数定义为虚函数,则会被编译为调用其非虚函数的析构函数,因为这个变量类型是基类类型,而多态是运行时特性,编译器无法判断这个对象是否是多态的,只能根据其类型来判断 。
407
+ 这可能也与虚基类的析构函数必须是虚函数有关,也与虚函数在机器码中的调用方式有关。虚函数调用被编译为机器码时,是通过对象的地址偏移调用的。当我们有一个基类类型的多态对象被delete时,如果你没有把基类的析构函数定义为虚函数,则会被编译为调用其非虚函数的析构函数,因为这个变量类型是基类类型,而多态是运行时特性,编译器无法判断这个对象是否是多态的,只能调用其类型的析构函数 。
408
408
409
- 而如果你把析构函数定义为虚函数,则会被编译为通过从地址偏移来调用 [[ ref]] ( https://www.cnblogs.com/chio/archive/2007/09/07/886337.html ) 。呈现的结果就是从运行时的虚函数表里找到析构函数的地址 ,然后将其调用。从上面的打印信息可以看出,基类和派生类的虚函数表里呈现覆盖关系的函数的偏移都是相同的,当一个多态的基类类型对象调用析构函数时通过偏移找到的将是派生类的析构函数 。
409
+ 而如果你把析构函数定义为虚函数,则会被编译为通过从地址偏移来调用 [[ ref]] ( https://www.cnblogs.com/chio/archive/2007/09/07/886337.html ) 。呈现的结果就是从运行时的虚函数表里通过偏移得到析构函数的地址 ,然后将其调用。
410
410
411
411
## 多继承
412
412
@@ -457,9 +457,9 @@ MySub (0x0x720da10) 0
457
457
458
458
- 可以发现有两个vptr,一个偏移16,一个偏移了64。对照Vtable,第一个偏移16就是指向MyBase的第一个虚函数,第二个偏移64指向的是MyDerived的第一个虚函数。
459
459
- MyDerived::dfunc1的前面两个东西已经说过了,其中offset=-16,其实是指MyDerived的虚函数表指针相对于MySub对象的指针偏移了16。为什么偏移了16,下面讲。
460
- - size=32,构成是 vptr MyBase(8字节) + MyBase.dataBase(4字节整型,但内存对齐到8字节) + vptr MyDerived(8字节) + MyDerived.dataDerived(对齐到8字节)。其中vptr MyDerived相对于首部的偏移为16。
461
-
462
- ## 引用
460
+ - size=32,构成是 vptr MyBase(8字节) + MyBase.dataBase(4字节整型,但内存对齐到8字节) + vptr MyDerived(8字节) + MyDerived.dataDerived(对齐到8字节)。其中vptr MyDerived相对于首部的偏移为16字节。
463
461
462
+ ## 参考
463
+ - [ 深入分析C++虚函数表] ( https://jocent.me/2017/08/07/virtual-table.html )
464
464
- [ C++对象模型] ( https://miaoerduo.com/2023/01/19/cpp-object-model/ )
465
465
- 《Inside the C++ Object Model》
Original file line number Diff line number Diff line change @@ -146,6 +146,3 @@ https://www.zhihu.com/question/35632207/answer/63936329)
146
146
答案是可以调用,但最好不要。构造函数调用时,指向虚函数表的指针还没被初始化,虽然确实可以调用,但只是作为成员函数,如果存在继承关系,这时派生类还没有构造,它不会调用到派生类的实现版本;
147
147
148
148
而对于析构函数,派生类析构后,基类调用的虚函数到底是自己的还是派生类的呢?若是调用基类实现则与运行时的版本不同,若调用派生类的,可能会访问到已回收的属性,所以最好不要这么干。
149
-
150
- ## 参考
151
- - [ 深入分析C++虚函数表] ( https://jocent.me/2017/08/07/virtual-table.html )
You can’t perform that action at this time.
0 commit comments