为什么会继续基类虚函数的默认形参?

以前在书上C++primer和Effective C++看到类似的内容,编写了程序然后输出结果确实是如此,但就是不知道为什么会这样。再者当时对汇编也不是特殊感兴趣,虽然能看懂简单的指令,后来看了斯坦福大学的范式编程公开课,开始对汇编有兴趣了,加上自己对底层很感兴趣,于是有了….

那为什么会重载基类的虚函数会继承默认形参?

举个粟子[为了在一张图上,就紧凑了些]:

通过基类指针或引用指向派生类对象会引发虚机制,P指针类型静态决议,而实际类型动态决议,故p->foo()会被编译器转会为如下形式:(*p->vptr[1])(p),真正调用要到运行时。这里引用虚函数表的第1个索引,第0项是存储类的基础信息,typeinfo类型,通过typeid返回该类型信息;

p->foo()则调用的是CDerived中的foo,直观上输出的是i22j33,但事实并不是如此。咱们还是看看汇编代码怎么转化我们程序的:

182行调用operator new分配sizeof(CDerived),CDerived占用的字节数是一个指向虚函数表的指针[8字节],加上父类的数据成员和子类的数据成员,这里每个成员已经对齐了且总大小也对齐。

= 16个字节[64位],182~183行中,rax保存了this指针的地址,info r rax时this=0x602010,185行esi中为20,即u的值,_ZN8CDerivedC1Ei为CDerived的构造函数【CDerived()-->CBase(),虽然在CDerived中没有显示调用CBase构造函数代码,编译器会为我们扩展CDerived()在用户代码前插入CBase()代码】;

CDerived()构造函数:

402行rbp-8处存放了this= 0x00602010,rbp-c为u=20,405行调用CBase构造函数:

319行的rax存放了this= 0x00602010,查看下x/wx 0x602010,即头四个字节显示的是0x00400c80,这个是什么值呢?下篇博客会介绍[测试机是小端表示法];

320行,x/4wx 0x602010,是:

0x602010:0x00400e50 0x00000000 0x0000000a 0x00000000,也就是this地址的该对象的内容。

321~323行重新赋值了this地址的内容:

0x602010:0x00400e10 0x00000000 0x0000000a 0x00000014,由0x00400c80变为0x00400c60,具体是什么下篇详细介绍,

195~197行分别是:rax=this,rax=0x602010,rcx=0x400bf6,rcx就是虚函数foo的地址了,后三行是准备两个默认形参值和this参数[每一个类的非static成员函数都会被编译器name mangling为唯一的名称,故会隐含一个const this指针,不可修改这个this的值],198行调用foo:

这里也没什么好讲的,就调用_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc_ZNSolsEi打印结果,所以打印了i1j2,并不是i22j33,即默认形参继承了基类的。

而o.foo(),则不会引发虚机制,并不会被转化成(*o.vptr[1])(&o),直接在编译期间静态决议为:_ZN8CDerived3fooEii(&o),使用c++filt则显示的是:CDerived::foo(int, int),那么打印的是i22j33,对应的汇编代码如下:

201~204行直接在栈上构造对象,获得o对象地址,然后调用构造函数CDerived,作用同上;

206~210是为准备调用foo时的参数,这里没有引发虚机制,所以打印的是i22j33。

添加了delete p; p = NULL;语句后[反汇编和GDB查看有些数值变化了,和上面不对应]:

195~196行比较p是否为空,rbp-18处的是this,je[jump equal]是的话就跳转到400a0c处,不为空的话,197~200分别是rax=this=0x602010,(rax)= 0x00400d70 [虚函数表],(rax) + 0x10为虚函数表中第二个虚函数[不知为啥+0x10],x/wx 0x400d80即为0x400d80 <_ZTV8CDerived+32>:0x00400c0e,x/xw 0x00400c0e即为0x400c0e: 0xe5894855; 然后顺便查看下x/wx 0x400d70为0x400d70 <_ZTV8CDerived+16>: 0x00400b44;201~203是准备调用0x400c0e [虽然虚函数表第二个索引是派生类的析构函数,但真正调用是发生在0x400bd4处的,不是太明白]:

418行调用~CDerived():

399行时:0x602010:0x00400d70 0x00000000 0x0000000a 0x0000001,进入到400af0后:

309行后:0x602010:0x00400db0 0x00000000 0x0000000a 0x00000014

在调用析构函数时会设置相应虚函数表,这么做的原因是防止在虚析构函数中调用虚函数,为了正确作出决议,在这里设置好了虚函数指针;剩余的是跳转到400b1c,然后再跳转,最后operator

delete(void*);

205行把P赋值为0;

栈上的o对象也是一样的逻辑,在退出main前会自动调用其析构函数。

由于在对象构造期间,是由最下层的构造函数往上调用,故先构造基类实例,此时实例并不完整,很多都没有配置妥当,比如上面先后赋值了this的虚函数指针,这里只是单继承。所有调用虚函数都会被决议为当前的,否则会下降到下层使用了未初始化的成员变量导致未定义行为。析构函数调用先构造最低层的,所以任何上层引用下层的行为都未定义,所以会被决议为当前的。

这里只是简单的列出编译器是如何转化我们的程序的,可能在背后调整了用户代码,后期分析派生类实例赋值给基类实例,虚函数指针是如何正确赋值的,从汇编语言层面揭露用户代码怎么被转化的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,176评论 5 469
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,190评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,232评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,953评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,879评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,177评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,626评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,295评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,436评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,365评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,414评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,096评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,685评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,771评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,987评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,438评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,032评论 2 341

推荐阅读更多精彩内容