中易网

pFun = ( Fun )*( ( int* ) * ( int* )( &b ) + i ); //啥意思?

答案:3  悬赏:80  
解决时间 2021-03-07 06:30
pFun = ( Fun )*( ( int* ) * ( int* )( &b ) + i ); //啥意思?
最佳答案
typedef void( *Fun )( void );//是吧Fun定义为一个没有参数,返回void类型的函数指针

*( ( int* ) * ( int* )( &b ) + i )这一段,
(int*)*相当于没有进行任何操作,所以等同于
*( ( int* )( &b ) + i )
这里先取b的地址,然后把地址转换成int*,之后+i是指针算术,也就是在b的地址上加一个int的长度,最后最前面的*是解指针,座椅这段最后返回的是“b的地址+i个int长度的值”
最前面的(Fun)是强制把“b的地址+i个int长度的值”转换为一个“没有参数,返回void类型的函数指针”,所以pFun就是一个函数指针,其指向的位置从一开始的b的地址,每次循环加一个int的长度

然后我们开看,b的地址,b是一个B类型,B类型的第一个函数是g(),而第一次循环pFun的地址就是b的地址,b又没有属性(私有或共有变量)所以b的地址就是b中第一个函数g的地址,所以第一次循环的pFun()相当于调用B::g

( Fun )*( ( int* ) * ( int* )( &b ) + i ); 这里*( ( int* ) * ( int* )( &b ) + i )最前面的*是对上面的结果进行解指针,也就取把b的地址+i个int长度的这个地址的值,并把它转换为Fun类型,也就是一个没有参数,返回void类型的函数指针,所以最后得到的就是一个函数指针。这个指针所指向的地址就是

然后我们来看循环,循环中3次pFun变量分别被赋了3次值,每次都是一个函数指针
由于B类型中有virtual函数,所以b的地址指向的是b的vtbl(如果你不知道这个,你面试就没戏了),vtbl可以看作一个保存了函数指针的数组,每个元素就是一个int长度,在vtbl中B::g,A::f,B::h是按照如上顺序排列的,所以第一次循环指向B::g,那么后两次就指向A::f和B::h了

至于为什么是按照这样的顺序排列的,是因为其声明顺序,首先是父类的virtual函数按照其生命顺序放入vtbl中,然后是子类的放进去,所以其顺序是:A::h,A::f(这是父类的声明顺序)子类中只有B::H是新声明的,所以顺序是A::g,A::f,B::h。
又因为b的类型是b,你知道什么事多态和动态绑定,就明白第一个调用的为什么是B::g而不是A::g了。

另外这道面试题对编译器进行了大量假设,估计出题的是个搞windows开发的,没见过别的平台,其实这道题在不同的编译器上得到的结果往往是不同的。 比如在我的64位mac上,这个代码是执行错误,segment fault,因为64位的vtbl每个元素长度是64,是2个int长。追答
追问:typedef void( *Fun )( void );//Fun pointer_inc//那void (*pointer_inc)(void )就是一个函数指针 对吧
*( ( int* ) * ( int* )( &b ) + i )这一段,//这个转化没问题啊?! *(Int*)(&b)+i)//这不是已经把地址内的值都取出之后,在强转为int* ?整数强转为指针?//*( ( int* )
(int*)*相当于没有进行任何操作,所以等同于
*( ( int* )( &b ) + i )
追答:pointer_inc 是一个函数指针,而不是void (*pointer_inc)(void )
你要分清楚类型和实例的区别
像typedef void( *Fun )( void )是定义了一个类型叫Fun,类型的声明是void(*)(void)
Fun本身就是个指针,不用加*
追问:*( ( int* ) * ( int* )( &b ) + i )
(int*)*相当于没有进行任何操作,所以等同于*( ( int* )( &b ) + i )
这一段,//这个转化没问题啊?! *(Int*)(&b)+i)//这不是已经把地址内的值都取出之后,在强转为int* ?整数强转为指针?//*( ( int* )
追答:&b是一个地址没错,(int*)(&b)是把一个地址转换成了指针,这种转换逻辑上是没有问题的。
指针有两个含义,一是它指向的地址,二是这个地址存放的数据的类型(仔细看这句话)
(int*)(&b) 其实是产生了一个指针,她的地址是b的地址,地址所存放的数据的类型是int类型
之所以要用int类型是因为int类型的长度正好是vtbl中每个元素的长度,这样+1的指针运算每次都能移动到vtbl中的下一个元素
追问:*( ( int* ) * ( int* )( &b ) + i )

* ( int* )( &b ) + i ) //这不是已经把地址内的值都取出之后
*( ( int* ) //在强转为int* ?整数强转为指针?
追答:因为这里的整数本身就是一个地址值

指针就是一个保存着地址整数值的整数,明白了么?
追问:不明白 中间) * ( 不是已经解引用了吗? 不是已经取出来了吗?
追答:假设b的地址是12345
那么&b = 12345,注意,你要把12345看作一个整数
(int*)(&b) 是一个指针就是(int*)12345就是把整数转换成指针,所以(int*)(&b)就是一个指向12345这个地址的int指针,你要明白,地址值也是个整数,
*(int*)(&b),这个相当于对一个指向12345这个地址的int指针解指针,得到的是12345这个地址开始的4个字节的内存,并把它当作一个int,而实际上,这4个字节是vptr,也就是指向vtbl的指针所在的位置。
(int*)*(int*)(&b)就是把把刚才那4个字节的int变成一个int指针,这个指针指向的位置就是vptr指向的位置,也就是vbtl的第一个元素

再看不懂只能自己想了,我只强调一点,在这里指针是一个保存着地址值的int类型
另外之前没有提到vptr,可能有点小错误
全部回答
其实很简单,网上有很多这样的代码,其实就是调用了b对象的virtual函数而已,你可以看到
A类里是:A::g()//A::f()/
B类里重写了A::g()所以就变成了:B::g()//B::f()//B::h()(注释:这个h()是B类里新加入的)。
现在可以看到那个循环就是B类的所有virtual函数了。
其实这里这段代码是用一个特殊的方式来调用b对象里系统给你维护的virtual函数表,这里涉及到了多态的本质,你可以网上找找,很多讲这样的文章,百度搜(虚拟函数内存模型)。
楼上说的也是正确的,这的确和编译器的实现有关,给你个连接,里面讲解的很详细易懂
http://blog.csdn.net/haoel/article/details/3081328
pFun = ( Fun )*( ( int* ) * ( int* )( &b ) + i ); //对对象b的地址转化为int* 地址,然后对其解引用,然后 强转为int* 再对其解引用???在强转为函数指针。
离开学校很多年了,现在不会了,早忘了。。
我要举报
如以上问答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
大商超市美食城我想知道这个在什么地方
未来日记特典完结篇在线观看!!!
“草()花开”成语是什么?
征信一年被查了20多次,但从来没有逾期过,请
上海迪士尼年末开放吗
夏天坐软垫会怎样?
英语小作文(六年级的)100个词题目是My friend
皇莎美容养生会所馨园店在哪里啊,我有事要去
根号2加1除以根号2减1,等于多少
卡通人物像戏子一样的女生叫什么
万万没想到番外篇5 10:33 那首英文歌叫什么?
海螺沟哪些自费项目值得去
速达软件入完凭证下一步干什么
潮州卫校怎么样?
西凤原浆酒NO.0188这个地址在什么地方,我要
推荐资讯
怎么查看别人手机短信记录短信内容
谁有一个靓的毛鸡叫声可以和我换一个水鸡或竹
碘131后四个月怀孕了可以要吗
向阳中路/城中路(路口)在哪里啊,我有事要去
宁波的环境问题有哪些?
脑子经常短片
给qq好友发信息,过一晚上在看消息列表里就没
第三个是“如”的成语(三个):一一一一一一一
四海镇怎么去啊,有知道地址的么
小胖精品水果在哪里啊,我有事要去这个地方
木木夕地址在哪,我要去那里办事
4.3÷2.1约等于多少?
手机登qq时,显示手机磁盘不足,清理后重新登
刺客的套装怎么选啊?