C++:多重继承:虚函数表、指针的位置问题

news/2024/11/27 4:34:17/

文章目录

  • 建议
  • 多重继承
  • 虚函数表
  • 虚函数表的存放位置,二进制文件

建议

需要看《深入理解C++对象模型》 这本书。

多重继承

多重继承就不应该存在,因为严重违反“简单原则”;不易理解,不易维护,不易开发。
就C++ Primer plus写到的一个例子说,一个工人衍生出歌唱家,和餐厅服务员,而如果一个工人既可以是歌唱家也可以是一个餐厅服务员。最后形成了一个会唱歌的餐厅服务员。其实是有违于类的一般通识。比如人属于动物,猪也属于动物,不能有一个动物既是人又是猪,虽然我们可以形容一个人如猪。
所以就工人衍生出歌唱家及餐厅服务员的例子,其实是工人作为一个实体,具有的技能是歌唱与服务。这一就好理解,工人可以拥有歌唱的技能,也可以拥有服务的技能。

本来就是不合理概念,大家还在试图讲解,而且讲解的还头头是道,这就造成学员的概念容易犯迷糊。

class istream : virtual public ios { … };
class ostream : virtual public ios { … }; 即使是虚继承多次基类,但是虚基类在对象内存布局里只出现一次。
In the case of virtual inheritance, only a single occurrence of the base class is maintained (called a subobject) regardless of how many times the class is derived from within the inheritance chain. iostream, for example, contains only a single instance of the virtual ios base class.

class A
{virtual void fun1(){};int a;
};class B
{virtual void fun1(){};int b;
};class D: virtual A
{virtual void fun1(){};int d;
};class E: virtual A
{virtual void fun1(){};int e;
};class F: A,B
{virtual void fun1(){};int f;
};
class G: D,E
{virtual void fun1(){};int g;
};int main()
{
F f;
G g;
return 0;
}(gdb) p f
$1 = {<A> = {_vptr.A = 0x400b98 <vtable for F+16>,a = 4195984},<B> = {_vptr.B = 0x400bb0 <vtable for F+40>,b = 0},members of F:f = 0
}
(gdb) p &(f.a)
$2 = (int *) 0x7fffffffe338
(gdb) p &(f.b)
$3 = (int *) 0x7fffffffe348
(gdb) p &(f.f)
$4 = (int *) 0x7fffffffe34c(gdb) p g
$5 = {<D> = {<A> = {_vptr.A = 0x400ac8 <vtable for G+88>,a = 0},members of D:_vptr.D = 0x400a88 <vtable for G+24>,d = 4196334},<E> = {members of E:_vptr.E = 0x400aa8 <vtable for G+56>,e = 4196893},members of G:g = 0
}(gdb) p &(g.a)
$6 = (int *) 0x7fffffffe328
(gdb) p &(g.d)
$7 = (int *) 0x7fffffffe308
(gdb) p &(g.e)
$8 = (int *) 0x7fffffffe318
(gdb) p &(g.g)
$9 = (int *) 0x7fffffffe31c如果类继承不加virtual,
会有两份A出现
(gdb) p g
$2 = {<D> = {<A> = {_vptr.A = 0x400a00 <vtable for G+16>,a = 4196334},members of D:d = 0},<E> = {<A> = {_vptr.A = 0x400a18 <vtable for G+40>,a = 4196765},members of E:e = 0},members of G:g = -136447344

虚函数表

看着网上的有些个博客写的也不太准确;

虚函数表指针,是虚基类的一个成员,是一个指针;使用gdb看时,这个指针被归到了基类块。 这个指针放在类定义的起始位置。对象的起始位置。

所以派生类对象的内存布局是:

SubClass
{BaseClass1{vtable *;BaseClass members;按照类定义里的顺序}SubClass members;
}class A
{virtual void fun1(){};int a;int b;
};class B
{virtual void fun1(){};int a;int b;
};
class C:A,B
{virtual void fun1(){};int c;int d;
};(gdb) p *c
$2 = {<A> = {_vptr.A = 0x4026b8 <vtable for C+16>, 虚函数表在 C 类定义的这个位置 如果又两个 相同的虚函数在两个基类里,其实用的是第一个的。a = 0,b = 0},<B> = {_vptr.B = 0x4026d0 <vtable for C+40>, 虚函数表在C 类定义的这个位置a = 0,b = 0},members of C:c = 0,d = 0
}这里,gdb自动将虚函数指针指向了函数表的函数地址表的位置,将运行时的类型给跳过了。起始在函数指针列表之前还有运行时类型的信息。

虚函数表的存放位置,二进制文件

是build到了 .rodata段。

  [13] .rodata           PROGBITS        00141a20 141a20 019b5c 00   A  0   0 32
(gdb) p *this
$5 = {<B> = {<A> = {_vptr.A = 0xf7772d88 <vtable for C+8>,(gdb) x /16x 0xf7772d88
0xf7772d88 <_ZTV10C+8>:    0xf7725aca      0xf7725ae4      0xf7722a72      0xf770fc1e
0xf7772d98 <_ZTV10C+24>:   0xf7711772      0xf771195c      0x00000000      0xf7772c98(gdb) disass 0xf7725ae4
Dump of assembler code for function _ZN10CD0Ev:0xf7725ae4 <+0>:       push   %ebp0xf7725ae5 <+1>:       mov    %esp,%ebp
(gdb) disass 0xf7722a72
Dump of assembler code for function _ZN10C19C0EPci:0xf7722a72 <+0>:       push   %ebp0xf7722a73 <+1>:       mov    %esp,%ebp0xf7722a75 <+3>:       push   %edi0xf7722a76 <+4>:       push   %esi0xf7722a77 <+5>:       push   %ebx0xf7622000 0xf77a6000   0x184000        0x0 /home/lib/liba.so0xf77a6000 0xf77a7000     0x1000   0x183000 /home/lib/liba.so0xf77a7000 0xf77a8000     0x1000   0x184000 /home/lib/liba.so# objdump -x /export/home/lss/lib/liba.so | grep 100a72
00100a72 g     F .text  00002e91              _ZN10C190CEPci(gdb) p /x 0xf7722a72-0x100a72
$6 = 0xf7622000
(gdb) p /x 0xf7772d88 - 0xf7622000
$7 = 0x150d88
(gdb) p /x 0x150d88 - 00141a20
Invalid number "00141a20".
(gdb) p /x 0x150d88 - 0x141a20
$8 = 0xf368[13] .rodata           PROGBITS        00141a20 141a20 019b5c 00   A  0   0 32objdump  -s --section=.rodata /home/lib/liba.so > /tmp/rem.out1150d70 00000000 00000000 00000000 00000000  ................150d80 00000000 00000000 00000000 00000000  ................   /// 这个是系统load so之后形成的一个表?150d90 00000000 00000000 00000000 00000000  ................150da0 00000000 00000000 00000000 00000000  ................150db0 00000000 00000000 00000000 00000000  ................

http://www.ppmy.cn/news/194102.html

相关文章

语义分割yolov5 v4.0 baseline快速复现 快速跑通 图像分割 图像分类 重新训练,训练结果,测试结果,实验图片-20210227

本机环境说明 操作系统版本 :~$ cat /etc/*release DISTRIB_IDUbuntu DISTRIB_RELEASE18.04 DISTRIB_CODENAMEbionic DISTRIB_DESCRIPTION"Ubuntu 18.04.5 LTS" NAME"Ubuntu" VERSION"18.04.5 LTS (Bionic Beaver)" IDubuntu ID_LIKEdebian PR…

【异步电机系列】电机参数离线辨识(含源码实现)

【一、闲话 很久没有认真更新自己的博客了&#xff01;正好这段时间在学习异步电机控制&#xff0c;所以把过程中的一些东西写下来&#xff0c;当是回顾也是备忘。本来想是把整个过程的问题和收获都记录下来的&#xff08;包括硬件设计、mcu控制、算法等&#xff09;&#xff0…

二进制包20分钟快速安装部署 Kubernetes v1.14.0 集群

文章目录 二进制包20分钟快速安装部署 Kubernetes v1.14.0 集群一 环境二 架构三 安装过程3.1 初始化脚本3.2 安装脚本3.3 安装失败回滚脚本 四 总结 二进制包20分钟快速安装部署 Kubernetes v1.14.0 集群 一 环境 操作系统Docker版本Kubernetes版本Etcd版本Flannel版本CentO…

bluetoothd源码剖析(一)启动流程

蓝牙系列&#xff1a; bluez调试笔记_weixin_41069709的博客-CSDN博客_bluezbluez移植https://blog.csdn.net/weixin_41069709/article/details/125168114?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22125168114%22%2C%22sour…

海思HI35XX之----音频模块使用总结

HI3518C /海思音频编解码 /海思音频数据帧头 /HI35XX音频编解码流程 /HI35XX音频属性配置 7722 https://blog.csdn.net/zqj6893/article/details/25562633 AUDIO 模块包括音频输入、音频输出、音频编码、音频解码四个子模块。音频输入和 输出模块通过对 Hi35xx 芯片 SIO …

PHP全栈学习笔记33

javascript能做什么&#xff1f; 语句与注解&#xff0c;标识符&#xff0c;字面量&#xff0c;变量命名规范 JavaScript中的数据类型&#xff0c;其它类型如何转为数据型&#xff0c;操作符 字符方法&#xff0c;数组方法&#xff0c;函数与对象&#xff0c;函数表达式&#…

色彩空间转换公式

一、 公式&#xff1a;基于BT.601-6 BT601 UV 的坐标图&#xff08;量化后&#xff09;&#xff1a; &#xff08;横坐标为u&#xff0c;纵坐标为v&#xff0c;左下角为原点&#xff09; 通过坐标图我们可以看到UV并不会包含整个坐标系&#xff0c;而是呈一个旋转了一定角度的…

YUV与RGB互转各种公式 (YUV与RGB的转换公式有很多种,请注意区别!!!)

YUV与RGB互转各种公式 (YUV与RGB的转换公式有很多种&#xff0c;请注意区别&#xff01;&#xff01;&#xff01;) 一、 公式&#xff1a;基于BT.601-6 BT601 UV 的坐标图&#xff08;量化后&#xff09;&#xff1a; &#xff08;横坐标为u&#xff0c;纵坐标为v&#xff…