C+ 关于类成员函数指针问题 作为函数参数传递过去后地址出现问题 贴上汇编

renhao120122 2013-02-23 08:22:42
我在一个类的成员函数中将这个类的另一个函数的指针作为参数传递给另外一个类的成员函数
在用函数指针调用的时候发现指针有问题
不知道什么原因 求解

调用的地方 :
pClassFun pCallFun = &Gameplus::NBomb::CreateFlower;
m_pMovieMaker->RegistMovie(pCallFun);

其中 :
#define CALLBACKPROXY Gameplus::NBomb
typedef void (CALLBACKPROXY::*pClassFun)();

运行到这里的 pCallFun值为0x00411a3c
而且测试 (this->*pCallFun )(); 正常调用

在RegistMovie的代码如下:
int CHrMovieMaker::RegistMovie(pClassFun pFun )
{
(m_pCallbackProxy->*pFun)();
}
这时候的pFun 值为0x00411a3c 但是运行到调用的时候报错


...全文
442 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
renhao120122 2013-06-08
  • 打赏
  • 举报
回复
这个问题一直没有解决。很奇怪的是如果我把命名空间去掉 那么就好用。这个模块是在一个别的项目里拿来的,在原来的模块里是可以运行的。后来改成回调接口实现了。也可以用boost库,但是项目里本来没有连接这个库,所以也不好加。回调接口用着没有问题。
lm_whales 2013-04-28
  • 打赏
  • 举报
回复
m_pCallbackProxy 没有贴出代码, 所以没有方法知道这个数据初始化没有,会不会出错。
lm_whales 2013-04-28
  • 打赏
  • 举报
回复
引用 19 楼 renhao120122 的回复:
[quote=引用 17 楼 lm_whales 的回复:] 这个,成员函数指针,不能胡乱传递的,只有静态函数可以像C的函数一样用指针传递函数 。 成员函数指针另有语法。 下面是成员函数指针的简单例子。 class C1{ int x,y; int setx(int x0){x=x0;}; int sety(int y0){y=y0;}; }; typedef int C1::(*funptr)(int); fun……
我知道这是成员函数指针,有知道有this参数,参考C++ 对象模型 174页 说明,非晶态成员函数地址是内存中真正的地址,但是要绑定于某个class object上,也就是说,它是真正内存的地址,只不过要绑定在某个类对象上。既然是地址,那么为什么不能传递,我不是传引用,就是拷贝,没有改变它的值,为什么用class 的指针调用它的函数会报错。[/quote] 因为这个函数有个隐藏参数 this指针,他需要一个A类的对象。 m_pCallbackProxy 必须有某种中途径,转换为Gameplus::NBomb类对象的指针; 这个指针,必须有一个真实存在的对象,和他相对应。 m_pCallbackProxy 不能是NULL指针,也不能是野指针。 PS: 1)注意指针转换有时会出错,那么就会有一个NULL指针。 程序崩溃。 2)如果m_pCallbackProxy没有初始化,或者初始化失败,就有了没有初始化的指针(野指针) 程序崩溃。 3) 如果m_pCallbackProxy初始化为NULL,并且没有重新赋值,那么就会有一个NULL指针。 程序崩溃。
lm_whales 2013-04-28
  • 打赏
  • 举报
回复
#include<iostream> using namespace std; class A{ public: A():x(0){}; A(int x0):x(x0){}; void func() { cout<<x<<endl; } private: int x; }; class B{ public: B():m_a(new A){}; B(int x):m_a(new A(x)){}; typedef void (A::*CallBackFunc)(); void registerFunc( CallBackFunc f) { (m_a->*f)(); } ~B(){delete m_a;} private: A *m_a; }; int main(int argc, char* argv[]) { B b(10); b.registerFunc(A::func); cout<<endl; return 0; }
renhao120122 2013-03-18
  • 打赏
  • 举报
回复
引用 17 楼 lm_whales 的回复:
这个,成员函数指针,不能胡乱传递的,只有静态函数可以像C的函数一样用指针传递函数 。 成员函数指针另有语法。 下面是成员函数指针的简单例子。 class C1{ int x,y; int setx(int x0){x=x0;}; int sety(int y0){y=y0;}; }; typedef int C1::(*funptr)(int); fun……
我知道这是成员函数指针,有知道有this参数,参考C++ 对象模型 174页 说明,非晶态成员函数地址是内存中真正的地址,但是要绑定于某个class object上,也就是说,它是真正内存的地址,只不过要绑定在某个类对象上。既然是地址,那么为什么不能传递,我不是传引用,就是拷贝,没有改变它的值,为什么用class 的指针调用它的函数会报错。
lm_whales 2013-03-15
  • 打赏
  • 举报
回复
这个,成员函数指针,不能胡乱传递的,只有静态函数可以像C的函数一样用指针传递函数 。 成员函数指针另有语法。 下面是成员函数指针的简单例子。 class C1{ int x,y; int setx(int x0){x=x0;}; int sety(int y0){y=y0;}; }; typedef int C1::(*funptr)(int); funcptr p[2]={C1::setx,C1::sety}; int main() { C1 c1; C1 *pc1=&c1; c1.p[0](10); c1.p[1](11); pc1->p[0](10); pc1->p[1](11); return 0; } 非静态成员函数里,隐藏了一个this指针,这个是C式样程序不能模拟的。 只有通过成员语法,才能正确调用; 存储成员函数指针,只能用成员语法,同样成员变量指针也有同样的成员语法
lm_whales 2013-03-15
  • 打赏
  • 举报
回复
搞错了要这个样子才行 class C1{ int x; int y; public: int setx(int x0){return x=x0;}; int sety(int y0){return y=y0;}; }; class C1_proxy {C1 &c; public: C1_proxy(C1& ref):c(ref){}; C * operator ->(){return &c;}; const C1 * operator ->()const {return &c;}; C1 & operator *(){return c;}; const C1 & operator *()const{return c;}; operator C1*(){return &c;} operator const C1 *()const{return &c;} }; typedef int( C1::*funcptr)(int) ; funcptr p[2]={&C1::setx,&C1::sety }; C1 c1,*pc1=&c1; (c1.*p[0])(10); (c1.*p[1])(11); (pc1->.*p[0])(10); (pc1->*p[1])(11);
赵4老师 2013-02-27
  • 打赏
  • 举报
回复
共享临时文本文件这种进程之间的通讯方法相比其它方法的优点有很多,下面仅列出我现在能想到的: ·进程之间松耦合 ·进程可在同一台机器上,也可跨机,跨操作系统,跨硬件平台,甚至跨国。 ·方便调试和监视,只需让第三方或人工查看该临时文本文件即可。 ·方便在线开关服务,只需删除或创建该临时文本文件即可。 ·方便实现分布式和负载均衡。 ·方便队列化提供服务,而且几乎不可能发生队列满的情况(除非硬盘空间满) ·……
赵4老师 2013-02-27
  • 打赏
  • 举报
回复
不要做A语言代码修改为B语言代码的无用功。 也不要做用A语言代码直接调用B语言代码库这样复杂、这样容易出错的傻事。 只需让A、B语言代码的输入输出重定向到文本文件,或修改A、B语言代码让其通过文本文件输入输出。 即可很方便地让A、B两种语言之间协调工作。
renhao120122 2013-02-27
  • 打赏
  • 举报
回复
引用 13 楼 tiewen 的回复:
普通的函数指针是函数的入口地址;但C++类的成员函数的指针不是,它至少不是一个直接可用的"地址"。它其实是成员函数在类中的偏移。 class C { public: int a();//偏移0 int b();//偏移1 int c();//偏移2 }; &C::a == 0; &C::b == 1; &C::c == 2; ……
你这个说法好像不对吧, 你看看《C++对象模型》
铁文 2013-02-26
  • 打赏
  • 举报
回复
普通的函数指针是函数的入口地址;但C++类的成员函数的指针不是,它至少不是一个直接可用的"地址"。它其实是成员函数在类中的偏移。
class C
{
public:
int a();//偏移0
int b();//偏移1
int c();//偏移2
};
&C::a == 0;
&C::b == 1;
&C::c == 2;
在传入前,IDE根据当前的上下文自动计算出了pCallFun的“绝对”地址:

传入后,上下文发生了变化:你肯定是在(m_pCallbackProxy->*pFun)();处或之前下的断点,此时pCallFun还未附加于任何上下文(Gameplus::NBomb对象),因此IDE显示其原来的值(偏移):

lz再仔细查查代码了
billzheng 2013-02-26
  • 打赏
  • 举报
回复
引用 10 楼 healer_kx 的回复:
billzeng,你先骂人就不对了。。。 赵四,你后骂人也不对。。。 讨论归讨论,我总觉得骂人不如打架。太没有涵养了。
骂骂赵狗,何错之有。一个精神病在论坛不断念经,而国内的论坛就是这种德性,没有人管。骂便骂了,等管理员来封我的帐号。
renhao120122 2013-02-26
  • 打赏
  • 举报
回复
杯具啊 解决问题的大神在哪里 !!!! 是不是C++bug啊 !!!! 是不是得用boost::function boost::bind啊 !!!
healer_kx 2013-02-25
  • 打赏
  • 举报
回复
billzeng,你先骂人就不对了。。。 赵四,你后骂人也不对。。。 讨论归讨论,我总觉得骂人不如打架。太没有涵养了。
太上绝情 2013-02-24
  • 打赏
  • 举报
回复
其实看汇编一定能看出来的,就是太费劲,是在不行导出一个静态函数包装一下吧
赵4老师 2013-02-24
  • 打赏
  • 举报
回复
崩溃的时候在弹出的对话框按相应按钮进入调试,按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。 To set a breakpoint when a variable changes value From the Edit menu, click Breakpoints. Click the Data tab of the Breakpoints dialog box. In the Expression text box, type the name of the variable. Click OK to set the breakpoint. VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 (Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。) 想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单! 指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认: 有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物; 而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。 这辈子不看内存地址和内存值;只画链表、指针示意图,画堆栈示意图,画各种示意图,甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗?本人深表怀疑! 这辈子不种麦不收麦不将麦粒拿去磨面;只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头,压面条,烤面包,……能从本质上理解面粉、理解面食吗?本人深表怀疑!! 提醒: “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 (Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。) 想要从本质上理解C指针,必须学习C和汇编的对应关系。” 不是一回事! 不要迷信书、考题、老师、回帖; 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实! 有人说一套做一套,你相信他说的还是相信他做的? 其实严格来说这个世界上古往今来所有人都是说一套做一套,不是吗? 不要写连自己也预测不了结果的代码! 电脑内存只是一个一维二进制字节数组及其对应的二进制地址; 人脑才将电脑内存中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、…… 对学习编程者的忠告: 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步对应汇编一行!
renhao120122 2013-02-23
  • 打赏
  • 举报
回复
引用 4 楼 taodm 的回复:
直接m_pCallbackProxy->CreateFlower();
你好 这样做肯定是可以的,上面的是个测试代码。其实函数指针值是放在一个结构体里传进去的 但是传入前和传入后的指针值发生了变化 看图:
上面是调用前参数的值


这些是调试到函数内参数的变化值

而且有个奇怪的现象 如果没有前面那个结果体参数的话 也就是我最开始的那种写法 最后的函数指针值是正确的
taodm 2013-02-23
  • 打赏
  • 举报
回复
直接m_pCallbackProxy->CreateFlower();
renhao120122 2013-02-23
  • 打赏
  • 举报
回复
引用 2 楼 taodm 的回复:
m_pCallbackProxy创建了正确的对象没有?
没有问题的 其实就是NBomb类的指针 作为回调的
taodm 2013-02-23
  • 打赏
  • 举报
回复
m_pCallbackProxy创建了正确的对象没有?
加载更多回复(1)

64,659

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧