C++ Member Function Pointer
说一说C++的成员函数指针。
在刚学C++的时候,一个基本的概念是指针的大小等于机器的字长。因此在32位的机器上,一个指向整型的指针sizeof会返回4。那么,是不是意味所有类型的指针sizeof后,都是4呢?
一般来说,绝对的事情是比较少的,特殊情况总是存在的,那就是成员函数指针。我们从简单的例子一点一点来看这个问题。
案例一:
class CBase1 {}; typedef void (CBase1::*FPbase1)(); int main() { size_t sizeFPbase1 = sizeof(FPbase1); cout << "sizeFPbase1 = " << sizeFPbase1 << endl; } |
OK,没啥特殊的,输出4。
再来看一个:
class CBase1 {}; class CDerive1 : public CBase1 {}; typedef void (CDerive1::*FPderive1)(); int main() { size_t sizeDerive1 = sizeof(FPderive1); cout << "sizeDerive1 = " << sizeDerive1 << endl; } |
还是4。那什么时候成员函数指针大小才会不等于4呢?请看下面这个例子。
案例三:
class CBase1 {}; class CBase2 {}; class CDerive2 : public CBase1, public CBase2 {}; typedef void (CDerive2::*FPderive2)(); int main() { size_t sizeDerive2 = sizeof(FPderive2); cout << "sizeDerive2 = " << sizeDerive2 << endl; } |
在VC下,你会发现sizeDerive2的大小是8,这是为什么呢?
一般来说,通用的解释就是:“这是有一定历史渊源的”。事实也确实如此。但是历史的事情,我就不说了,大家自己google好了。这里以VC为例,做一个简单介绍(WARNING:GCC等其他编译器在实现上是存在不同的)。
我们知道C++里有一个关键字叫this。对于CDerive1来说,这个类对象的this (简称CDerive1-this)和CBase1 (CBase1-this)是一样的。但是对于CDerive2-this来说,情况有所不同。如果是用来调用CBase1中的成员函数,没什么问题。但是当调用CBase2中的成员函数时,该怎么办?总不能拿CBase1-this来搞吧?
因此,在VC中,这个成员函数指针有两部分组成,一部分是CDerive2-this,还有一部分用于调整CDerive2-this。下面用一个简单的例子来证明下。
案例四:
int main() { FPderive2 fpDerive2 = nullptr; FPbase2 fpBase2 = nullptr; fpDerive2 = fpBase2; } |
怎么证明呢?先来看汇编吧。
; 46 : FPderive2 fpDerive2 = nullptr; mov DWORD PTR $T5371[ebp], 0 ; 47 : FPbase2 fpBase2 = nullptr; mov DWORD PTR _fpBase2$[ebp], 0 ; 48 : mov eax, DWORD PTR _fpBase2$[ebp] |
首先看一下高亮的那几行。很明显地你会发现同样是初始化,fpDerive2和fpBase2产生的汇编码完全两样。fpDerive2占用了2个DWORD区域,而fpBase2只占用了1个DWORD。这里解释了sizeof为什么一个返回8一个返回4。
再看fpDerive2 = fpBase2。
; 49 : fpDerive2 = fpBase2; mov eax, DWORD PTR _fpBase2$[ebp] |
注意高亮部分。这里我们看到,fpDerive2的高DWORD区域被置1了。如果我们的代码是fpDerive2 = fpBase1会是什么情况呢?试一下,你就会发现,fpDerive2的高DWORD区域被置0了。所以,我们有理由相信高DWORD区域是被用来存放一个调节变量的。
那么,低DWORD用来存放什么呢?自己试吧,简单说就是this。
这里,我们考虑的情况还只是多重继承。如果是虚继承又会发生什么情况?如果一个类只有一个前置声明,那么它的成员函数指针大小是多少?这些情况会更复杂。有兴趣的同学可以参考下面几篇文章做更细致的研究。
- Pointers to member functions are very strange animals
- Answer to exercise: Pointer to member function cast
- Member Function Pointers and the Fastest Possible C++ Delegates
更新(4/12/2012):研究了下FastDelegates的代码,针对VC,好像我的理解还是有点偏差。
posted on 2012-04-05 23:04 wpcockroach 阅读(1062) 评论(0) 编辑 收藏 举报