📄 subject_56230.htm
字号:
<p>
序号:56230 发表者:xiongli 发表日期:2003-10-16 11:50:04
<br>主题:成员函数指针
<br>内容:#include "stdio.h"<BR>class A<BR>{<BR> public:<BR> virtual void t(){<BR> printf("base\n");<BR> };<BR> virtual void t2()<BR> {<BR> };<BR> int rt()<BR> {<BR> printf("non virtual func\n");<BR> return 1;<BR> };<BR><BR>}; <BR>class B:public A<BR>{<BR>public:<BR> virtual void t(){<BR> printf("derive\n");<BR> };<BR> virtual void t2(){};<BR>};<BR>void justfun()<BR>{<BR>int a;<BR>a=0;<BR>};<BR> <BR>int main()<BR>{<BR> A *p; <BR> B O;<BR> p=&O;<BR> int(*cast)();<BR> void(*nof)();<BR> void(A::*pmf)();<BR> int(A::*rpmf)();<BR> nof=&justfun;<BR> rpmf=&A::rt;<BR> pmf=&A::t2;<BR>// cast=(int * ())(rpmf);<BR> __asm<BR> {<BR> push eax<BR> mov eax,rpmf<BR> mov cast,eax<BR> pop eax<BR> }<BR> printf("%x %x %x\n",nof,pmf,rpmf);<BR> (*cast)();<BR> (*nof)();<BR> (p->*rpmf)();<BR> (O.*pmf)();<BR> (p->*pmf)();<BR> pmf=&A::t;<BR> (p->*pmf)();<BR> p->t2();<BR> return 0;<BR>}<BR>今天早上看到一个朋友的留言,关于通过成员函数指针调用成员函数的问题。<BR>成员函数指针调用跟普通函数指针调用不同。<BR>因为成员函数有虚函数和非虚函数的差别,调用的时候,跟普通非成员函数调用有不同。<BR>对于非成员函数,取函数名的地址,得到的就是该函数内存中的起始地址,然后直接调用就可以。在汇编层面上,就是直接call addr.<BR>对于非虚成员函数,取得的地址其实也就是完整的函数地址。可以直接调用。但是因为类型的原因,不能把成员函数的地址直接给一个普通的函数指针。成员函数指针的类型是classname::ptr的形式,而且是thiscall,thiscall是c++保留关键字,所以无法直接给一个普通的函数指针,用强制转换也不行。因为c++不允许对函数指针类型做强制转换,所以我在上面的代码中用嵌入汇编,完成强制转换,通过调用,发现上面的理解是正确的。<BR>对于虚成员函数就比较麻烦。如果不用指针调用,编译器就直接把object的地址放到ecx中,其实也就是vtable的地址,然后在这个vtable上就可以找到正确的函数。如果通过指针调用,编译器无法保证这个指针以后会不会发生变化,也就是说这个指针变量,以后可能会指向这个class的其他成员函数,所以编译器一旦检测到这种&classname::funcname的时候,就会生成一个vcall,然后把vcall的地址作为&classname::funcname的结果返回。vcall其实指向的是一组代码,大概如下形式:<BR>mov eax,[ecx]<BR>call [eax+n]<BR>其中n是根据不同funcname在vtable中不同偏移决定的。前面说过,如果不通过指针调用,编译器可以根据函数名字找到偏移,但是通过指针,编译器就找不到名字了,找到的是一个地址,所以必须在地址上强制生成这个n.所以代码的作用就是在vtable,也就是[ecx]中,找到正确的函数。<BR>上面的结论是我调试出来的,大家可以在中间放断点,通过alt+8查看汇编代码,得到结论。<BR>同时c++标准没有规定编译器实现细节,上面的东西只对vc6 debug模式下有说明作用。
<br><a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p>
<hr size=1>
<blockquote><p>
<font color=red>答案被接受</font><br>回复者:紫君 回复日期:2003-10-16 19:05:19
<br>内容:可以领分吗?
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:xiongli 回复日期:2003-10-16 21:24:27
<br>内容:当然<BR>分从哪里来,偶就送到那里去
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:紫君 回复日期:2003-10-17 08:48:09
<br>内容:<BLOCKQUOTE>引用“第2楼”所言<BR><Q>当然 分从哪里来,偶就送到那里去</Q></BLOCKQUOTE><BR>赫赫.......礼尚往来,分会送还给你的<BR>
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:紫君 回复日期:2003-10-17 08:54:23
<br>内容:http://www.vchelp.net/cndevforum/subject_view.asp?subject_id=55521&forum_id=
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:coolleo 回复日期:2003-10-17 08:56:30
<br>内容:赫赫有名的xiongli大侠好大方啊!!!!^_^
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:紫君 回复日期:2003-10-17 08:59:05
<br>内容:俺也很大方地,虽然俺不是大虾
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:市长先生 回复日期:2003-10-17 16:47:22
<br>内容:成员函数指针的类型是classname::ptr的形式,而且是thiscall,thiscall是c++保留关键字,所以无法直接给一个普通的函数指针,用强制转换也不行。<BR>我抗议:<BR> 可以用强转换赋值给普通指针。<BR><BR>class A<BR>{public:<BR>A(int t):_a(t){}<BR>const int _a;<BR>};<BR>int main()<BR>{<BR>A* pa=new A(5);<BR>int* pi;<BR>pi=reinterpret_cast<int*>(pa);<BR>*pi=7;<BR>cout<<pa->_a<<endl;<BR>}<BR>没有意外的话,输出为7,不仅把pa给了pi,而且把pa的常量成员_a也修改了.<BR>
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:xiongli 回复日期:2003-10-17 17:06:20
<br>内容:我没有试reinterpret_cast<BR>不知道可不可以。现在在实习,没有vc<BR>不过楼上的转换的不是函数指针
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:紫君 回复日期:2003-10-17 18:30:41
<br>内容:试了一下,结果输出为7<BR><BR>悄悄地问:xiongli,你在什么公司实习呀,做什么开发<BR>2003-10-17 18:35:40
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -