漫谈析构函数(一)——从一个面试题开始

  • 时间:
  • 浏览:1
  • 来源:uu快3官网_uu快3登入

思考几分钟,看一下守护线程输出:

首先,由守护线程中typedef说说大伙 儿知道Fun是一四个多函数指针,也因此我这句话是要将某个地址转去掉 函数地址(指针)。具体步骤如下:

综上,大伙 儿还可不能否知道这句活因此我根据i的递增逐个调用B中的虚函数。B中的虚函数布局大伙 儿原困知道,可是我输出就没办法 理解了。

(3) (Fun)*((int*)*(int*)(&b)+i)----------------------------得到vptr地址中存放的内容,即vptr(原困说vptr的值,原困说vtbl的地址)。

(1) (Fun)*((int*)*(int*)(&b)+i)----------------------------取对象b的地址,由对象的内存布局大伙 儿知道对象b的地址和vptr的地址相同,即取vptr的地址。

(2) 继承自base Class的没办法 被override的虚函数。

1. 一四个多虚函数表(vtbl)会被编译器产生出来,实物存放Class的虚函数地址。(虚函数表是以Class维护的)

3. 对虚函数的调用会被改写,比如b.f(),f()为虚函数)会被改写成:(*b.vptr[1])(&b),其中1表示f()vtbl中的索引,&b代表调用f()this指针。(还可不能否看出虚函数的调用是时需以间接调用完成,下行速率 相对普通成员函数要低)

从上图还可不能否看出A,B的对象中没办法 数据成员,还可不能否一四个多vptr,这名 大伙 儿还可不能否输出验证:

    相信不少人对守护线程中这条说说就有迷惑,下面大伙 儿来逐步分析下这条说说的含义。

(6) (Fun)*((int*)*(int*)(&b)+i)-----------------------------人太好上一步因此我将指针移动到vtbl中相应表条目处(存放虚函数的地址),可是我这里取出地址的内容因此我对应虚函数的地址。

(1) 被当前Class覆盖(override)的base Class中的虚函数

      (aClass A内存布局                           (bClass B 内存布局

在以后现在开始大伙 儿的内容前,首先让大伙 儿看一道面试题,题目如下:

2. 每一四个多Class Object中,一四个多额外的虚函数表指针(vptr)会被编译器合成出来,内含vtbl的地址。vptr是以Class Object维护的)

注:通过这名 例子大伙 儿还发现了一四个多难题,函数f()在基类A中是私有的,而大伙 儿却访问到了。人太好大伙 儿将B中的h()声明为private,输出结果依然不变,无须会引起访问权限难题。也因此我说还可不能否外界访问到Class的私有虚函数。这是为何呢?我买车人的理解是:访问限定符只在编译检查完后 起作用,而在守护线程执行期间没办法 作用,原困从C++的函数名称修饰规则来看,并没办法 将访问限定符纳入其中,可是我大伙 儿因此我通过了编译,找到对应的函数地址就还可不能否调用私有函数,原困在内存中私有函数和公有函数并没办法 什么区别。

蕴藏一四个多虚函数的Class,以下3个操作会在编译期间居于:

    原困你有难题,原困不理解,大伙 儿就开彻底分析下这名 守护线程。首先简单讨论一下虚函数在内存中与Class的关系。

(7) (Fun)*((int*)*(int*)(&b)+i)------------------------------最后这名 步将函数的地址转去掉 函数指针,完后 后边调用。

说出下段代码的输出:

    说了没办法 多,大伙 儿基本还可不能否推断出守护线程中Class A,Class B的内存布局情況,如下图。注:Type_info完后 讨论,这里先忽略。

(2) (Fun)*((int*)*(int*)(&b)+i)----------------------------vptr的地址强转成int型地址(指针),即让编译器将vptr的地址当做int型指针对待。因此我*(&b)会被当做对象b

(3) 纯虚函数(当前类定义的,原困从base Class继承来的)

注:虚函数在vtbl中的顺序和虚函数在Class中的声明顺序一致。

没办法 虚函数表中的“虚函数”都包括什么呢?总共有以下三类:

(5) (Fun)*((int*)*(int*)(&b)+i)---------------------------- 大伙 儿知道指针与整数的相加,移动的是指针所指对象的大小,原困上一步原困转换为int型指针,可是我会移动i*sizeof(int)个字节。

此外蕴藏一四个多虚函数的Class的默认合成构造函数以及拷贝构造函数不再是trivial,他时需为每个Objectvptr设定初值,使其指向适当的vtbl

  

扩展:同理当一四个多Class直接或间接继承一四个多virtual base Class时,因此我再表现“位逐次拷贝语义”,默认构造函数和拷贝构造函数因此我再是trivial,原困时需正确的设置virtual base Class的偏移。

cout<<sizeof(A)<<"  "<<sizeof(B)<<endl;(4,4)。

注:如图:一四个多B的对象之间或一四个多D的对象之间调用拷贝构造,“位逐次拷贝”不让居于难题,因此我用D的对象给B的对象赋值(此时造成切割)就时需调整vptrvirtual base Class偏移。

 

(4) (Fun)*((int*)*(int*)(&b)+i)----------------------------vtbl的地址转为int指针,为完后 与整型类型i相加做准备。