前几天看了July哥的博客http://blog.csdn.net/v_JULY_v/archive/2011/05/26/6446364.aspx#1685620,讲的非常好,其中有一个问题不知是因为解释的不清楚,还是因为我的水平有限,一直没想明白。
Fun pFun = (Fun)*((int*)*(int*)(&d)+0);各种指针转换、取地址,让哥凌乱了。今晚上理了一下,写在下面:
首先是随便搞的测试代码:
主要看一下比较有代表性的pFun_3(),为了清楚起见,我们引用了July博客中的图片:
1、对于一个对象来说(例如代码中的c),其首地址所存储的是“指向第一个虚表的指针”,该指针也就是第一个虚表的首地址。
2、我们通过*操作符来取其元素(取“指向第一个虚表的指针”)。有人想直接这样:*(&c),这可不行!&c是Child型变量的地址,可取不到“指向第一个虚表的指针”;这时候得进行指针转换。
3、指针转换的类型要看你要取元素类型的大小。我们知道,指针的存储空间为4字节,所以我们要把&c首先转换成指向4字节类型的指针,再使用*操作符取其元素。这恐怕也就是*(int*)(&c)的来历了。既然这个指针转换的类型只与元素大小有关,我们也可以*(unsigned *)(&c)或者*(f*)(&c)甚至*(char ********)(&c),只要指针指向的是一个4字节类型就可以。
4、好了,我们取到了第一个虚表的首地址,但是同样的问题又出现了,虽然虚表的首地址得到了,但是要想取出虚表中的元素,还得根据元素类型的大小进行指针转换,我们知道,元素又是指针!那好吧,还是用(int *)转,谁让int型占4字节呢!然后就有了*(int *)*(int*)(&c)。这时候就得到了虚表中的元素--(虚)函数指针,再进行一个函数指针的转化就可以调用了。
5、至于那些+1和+2之类的东西,也是(int *)的转换的原因,否则如果(&c)+1,那可就直接加了个sizeof(class Child),取的不是“指向第二个虚表的指针”的地址,而是跑到对象存储空间的结尾去了。
从问题表面分析了一下,至于更加深入的问题还需要进一步的学习啊!
以上总结纯属个人思路,没有经过权威认证,还望各位高手多多指教!