函数成员函数为什么不可以当着回调函数

max_xy 2005-05-18 02:32:11
最近我在把一个opensource得项目封装成一个类,碰到一个麻烦,就是这个项目当中大量使用回调函数,原来这些函数都是全局函数,我现在为了保证封装,把这些函数都封装成全局函数,这样一来,这些函数就不能当着回调函数了,我估计是类的成员函数实际上有一个隐形参数,也就是this指针,这样一来的话,不知道我理解的对不对,虽然我知道把成员函数改为静态函数可以达到我的目的,但是静态函数里不能使用普通的成员变量,但是如果成员变量改成静态变量,又达不到封装的效果,
唉,我该怎么办!!!!
...全文
328 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
max_xy 2005-05-20
  • 打赏
  • 举报
回复
多谢各位的热情,没有想到这么一个普通的问题得到大家这样的讨论,谢谢。揭帖!
xjp6688 2005-05-20
  • 打赏
  • 举报
回复
路过+学习
jingyueid 2005-05-19
  • 打赏
  • 举报
回复
#include <iostream >

class Test
{
public:
void output(int i)
{
std::cout < < i < < std::endl;
}
};
template <class _T > void
callback(_T* pthis, void(_T::*pmemfunc)(int), int param)
{
(pthis- >*pmemfunc)(param);
//为什么这里直接(*pmemfunc)(param)不可以?既然是函数入口地址,为什么前面还要pthis->
/ /pmemfunc不可以被直接调用,是_thiscall类型,这种调用需要先传递一个this指针近来
//在上面已经解释过了,C++既然不允许显式的调用pmemfunc(pthis, param)
//只好使用C++风格的pthis->pmemfunc()
}


int main()
{
Test a;
callback <Test >(&a, &Test::output, 1);
return 0;
}
zhangbiao1981 2005-05-19
  • 打赏
  • 举报
回复
(*pmemfunc)(param)不可以,因为它的类型声明为void(_T::*pmemfunc)(int), 是一个成员函数指针类型。所以只能使用成员函数指针操作符->*
也就是(pthis->*pmemfunc)(param);
GEATA 2005-05-18
  • 打赏
  • 举报
回复
学习
max_xy 2005-05-18
  • 打赏
  • 举报
回复
谢谢楼上各位的回复,高手真多
但是看完后,我还是有几个小问题不解,也许是钻牛角
具体问题见下面代码中
#include <iostream >

class Test
{
public:
void output(int i)
{
std::cout < < i < < std::endl;
}
};
template <class _T > void
callback(_T* pthis, void(_T::*pmemfunc)(int), int param)
{
(pthis- >*pmemfunc)(param);
//为什么这里直接(*pmemfunc)(param)不可以?既然是函数入口地址,为什么前面还要pthis->
}


int main()
{
Test a;
callback <Test >(&a, &Test::output, 1);
return 0;
}
zhangbiao1981 2005-05-18
  • 打赏
  • 举报
回复
最简单的方法使用标准库中的函数对象来用作回调函数。例如,用mem_fun(&Shape::draw))
就可以将Shape类中的draw函数做成一个函数对象。在需要传递函数指针的地方将mem_fun(&Shape::draw))串递过去就行。
umbrella1984 2005-05-18
  • 打赏
  • 举报
回复
回调函数跟C++有什么关系?
visual4825 2005-05-18
  • 打赏
  • 举报
回复
Jinhao(辣子鸡丁)(写一个new money的死循环, 结果我被钞票淹)

强!佩服!对C++真的理解很深啦。
~~~~~~~~
同意,
lanshigang1984 2005-05-18
  • 打赏
  • 举报
回复
社区怎么不能提问啊?
我们正在做C语言课程设计,我忙一个星期了,代码是写出来了
但是老是不能编译成功,我很急啊,明天就要交上去了啊,
请高手帮我看看,小弟在此谢过了!
题目是这样子的:
做一个学生成绩管理系统,要求如下:
1.主要功能:
(1) 能按学期、按班级完成对学生成绩的录入、修改 (1-3用函数实现)
(2) 能按班级统计学生的成绩 的总分及均分,并能根据学生的平均成绩进行排序 (TOTAL、AVERAGE、)
(3) 能查询学生成绩,不及格科目及学生名单(有相应的提示:请输入学号)。。。。。。)(4) 能按班级输出学生的成绩单
2.要求: 界面友好,易于操作

以下是我编的程序:
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<conio.h>

#define MAXSIZE 100
#define ADDSIZE 50
#define PT elem+l->length
#define N 4
typedef struct term{/*班级和学期的结构体*/
char class1[10];
char term1[10];
}term;
typedef struct student{/*学生成绩信息的结构体*/
term st;/*班级和学期结构体放于此结构体中*/
char num[10];
char name[12];
float course[4];
int total;
int average;
int bit;
}lnode,*stu;

typedef struct{
lnode *elem;/*指向上个结构体的指针*/
int size;/*最大能放lnode结构体成员的个数*/
int length;/*当前长度*/
}sqack,*sq;
sqack *l;
void init(void)/*动态分配存储空间*/
{l->elem=(stu)malloc(MAXSIZE*sizeof(lnode));
l->length =0;
l->size=MAXSIZE;
}


int input(void)/*输入学生的信息*/
{lnode *newbase,*p;
char cla[10],ter[10],ch;
int n,i;
if(l->length>=l->size){
newbase=(stu)realloc(l->elem,(l->size +ADDSIZE)*sizeof(lnode));/*追加存储空间*/
l->elem =newbase;
l->size +=ADDSIZE;
}
p=l->elem;
do
{printf("输入班级和学期(学期用这种格式,如2005年上学期 2005 1,2005年下学期 2005 2;先输入班级,回车后再输入学期)\n");
gets(cla);
gets(ter);
printf("要输入多少个名单?");
scanf("%d",&n);
printf("输入学生的成绩\n学号\t姓名\t科目1\t科目2\t科目3\t科目4\n");
for(i=0;i<n;i++)
{scanf("%s%s%d%d%d%d",p->num ,p->name,p->course[0],p->course[1],p->course[2],p->course[3]);
strcpy(p->st.class1,cla);
strcpy(p->st.term1,ter);
++l->length ;}
printf("要继续吗?(y/n)");
ch=getchar();}while(ch=='Y'||ch=='y');
}
int change()/*修改学生的信息*/
{lnode *p;
lnode e;
int flag=1,i;
char s1[10],num1[10];
printf("输入学期和学号(输入学期以后按回车再输入学号):\n");
gets(s1);
gets(num1);
p=l->elem ;
while(p<=(l->elem+l->length ) && flag==1)/*查找要修改的学生的信息*/
{if(strcmp(p->num,num1)==0&&strcmp(p->st.term1,s1)==0);
flag=0;/*找到了*/
p++;}
p--;
if(flag==1) printf("找不到此学号!\n");

printf("%s %s",p->num,p->name);
for(i=0;i<N;i++)
printf("%d ",p->course[i]);
printf("\n");
printf("输入修改信息\n");
scanf("%s%s%s%s",e.st.class1,e.st.term1,&e.num,e.name);
for(i=0;i<N;i++)
scanf("%d",&e.course[i]);
*p=e;
}
void stat()/*统计学生的成绩*/
{lnode tt[50];
char ter[10],clas[10];
int i,k;
printf("请输入学期和班级(输入学期后按回车再输入班级):\n");
for(i=0;ter[i]!='\n';i++)
ter[i]=getchar();
for(i=0;clas[i]!='\n';i++)
clas[i]=getchar();
same(ter,clas,tt,&k);/*把学期和班级相同的学生信息放在结构体数组tt中*/
sort(tt,&k);/*按学生成绩从高到低排序函数*/
print(tt,&k);/*输出学生的成绩*/
}

void same(char *t1,char *t2,lnode *t,int *k) /*把学期和班级相同的学生信息放在结构体数组tt中*/
{int i=0;
lnode *p,*q;
q=t;
p=l->elem ;
while(p<=l->elem+l->length )
{if(strcmp(p->st.term1,t1)==0&&strcmp(p->st.class1 ,t2)==0)
{*q=*p;q++;
i++;}
p++;}
*k=i;
}
int sort(lnode *p,int *k)/*按学生成绩从高到低排序函数*/
{int i;
lnode *q,temp;
for(q=p;q<p+ *k;q++)
{q->total =0;
for(i=0;i<N;i++)
q->total =q->total +q->course [i];
q->average =q->total /N;
}
for(i=0;i<*k-1;i++)
for(q=p;q<p+*k-1-i;q++)
if(q->total<(q+1)->total){temp=*q;*q=*(q+1);*(q+1)=temp;}
}
void print(londe *q,int *k)/*输出学生的成绩*/
{int n;
lnode *p;
p=q;
for(p=q;p<q+*k;p++)
{printf("%s %s",p->num,p->name);
for(i=0;i<N;i++)
printf("%d ",p->course[i]);
printf("%d %f",p->total,p->average);
printf("\n");}
}
void search()/*查找学生的成绩*/
{char ch;
do
{printf("1 按学号查询\n2按姓名查询\n");
ch=getchar();
switch(ch)
{case '1': 1search();break;
case '2': 2search();break;
default:printf("错误!\n");
}printf("要继续查找吗?(y/n)");
ch=getchar() } while(ch=='y'&&ch=='Y');
}
void 1search()/*按学号查*/
{lnode *p;
char ter1[10];
int i,flag=1;
p=l->elem;
printf("输入学号:");
gets(ter1);
for(p=l->elem;p<l->PT;p++)
{if(strcmp(p->num,ter1)==0)
{flag=0;
printf("%s %s ",p->st.term1,p->st.class1);
printf("%s %s ",p->num,p->name);
for(i=0;i<N;i++)
printf("%d ",p->course[i]);
printf("%d %3.1f",p->total,p->average);
printf("\n");}}
if(flag) printf("没有找到!");
}
void 2search()/*按姓名查*/
{lnode *p;
char ter1[10];
int i,flag=1;
p=l->elem;

printf("输入姓名:");
gets(ter1);
for(p=l->elem;p<l->PT;p++)
{if(strcmp(p->name,ter1)==0)
{flag=0;
printf("%s %s ",p->st.term1,p->st.class1);
printf("%s %s",p->num,p->name);
for(i=0;i<N;i++)
printf("%d ",p->course[i]);
printf("%d %f",p->total,p->average);
printf("\n");}
}
if(flag) printf("没有找到!") ;
}
void fail()/*查找不及格及学生名单*/
{int i;
lnode *p;
for(p=l->elem;p<l-> PT;p++)
{ for(i=0;i<N;i++)
if(p->course[i]<60)
{printf("%s %s ",p->st.class1,p->st.term1);
for(i=0;i<N;i++)
printf("%d ",p->course[i]);
printf("%d %f ",p->total,p->average);
printf("\n");}}
}
void output()/*按班级输出学生的成绩单*/
{lnode tt[50];
int k;
char clas[10],ter1[10];
printf("输入要查询的班级和学期(输入班级后按回车输入学期):\n");
gets(clas);
gets(ter1);
same(ter1,clas,tt,&k);/*/*把学期和班级相同的学生信息放在结构体数组tt中*/*/
print(tt,&k);/*输出学生的成绩*/
}


int main()
{char ch;
do
{printf("请选择:\n");
printf("1 对学生成绩的录入\n2 对学生成绩的修改\n3 统计学生成绩\n4 查询学生成绩\n5查找不及格科目及学生名单\n6 按班级输出学生成绩单\n ");
ch=getchar();
switch(ch)
{case '1': input();break;
case '2':change();break;
case '3':stat();break;
case '4':search();break;
case '5':fail();break;
case '6':output();break;
default:printf("错误!\n");
}
printf("要继续吗?(y/n)");
ch=getchar();
}while(ch='y'||ch='Y');
return;

}
jingyueid 2005-05-18
  • 打赏
  • 举报
回复
借 Jinhao(辣子鸡丁)(写一个new money的死循环, 结果我被钞票淹) ( ) 的代码。

可以如下回调:
#include <iostream>

class Test
{
public:
void output(int i)
{
std::cout << i << std::endl;
}
};
template<class _T> void
callback(_T* pthis, void(_T::*pmemfunc)(int), int param)
{
(pthis->*pmemfunc)(param);
}


int main()
{
Test a;
callback<Test>(&a, &Test::output, 1);
return 0;
}

比以前多传一个this指针。OK了!
jingyueid 2005-05-18
  • 打赏
  • 举报
回复
用汇编就好了,没有类型检查,只要把参数传对就一切OK。
jingyueid 2005-05-18
  • 打赏
  • 举报
回复
学习
yueyixing 2005-05-18
  • 打赏
  • 举报
回复
你可以看一下李维的《inside VCL》,那里面有delphi是怎么解决这个问题的方法,好像是用汇编直接操作的。
horisly 2005-05-18
  • 打赏
  • 举报
回复
Jinhao(辣子鸡丁)(写一个new money的死循环, 结果我被钞票淹)

强!佩服!对C++真的理解很深啦。
horisly 2005-05-18
  • 打赏
  • 举报
回复
对象函数在编译时候,会在参数列表末插入一个this指针。所以,当你把回调函数声明为对象函数时候,让操用系统调用时,操作系统发现多出一个参数,而致使程序运行失败。

呵呵,上面几个的解释很精辟了
mostideal 2005-05-18
  • 打赏
  • 举报
回复
up
yangjundeng 2005-05-18
  • 打赏
  • 举报
回复
楼上的正解
Jinhao 2005-05-18
  • 打赏
  • 举报
回复
全因为那个this
不要去猜测编译器的实现!

一个给系统回调的函数通常带有一个参数,用于传递给这个函数,比如创建一个线程 就需要
void()(void*); 这样的函数

如果想对某个类的成员函数进行回调,那么就要增加一个间接层来解决这个问题

class helper
{
public:
virtual ~helper(){}
virtual void call() const = 0;
};

template<typename _T>
class entity: public helper
{
public:
entity(_T* pthis, void(_T::*pmemfunc)(int), int param)
:pthis_(pthis), pmemfunc_(pmemfunc), param_(param)
{}

void call() const
{
(pthis_->*pmemfunc_)(param_);
}
private:
_T* pthis_;
void(_T::*pmemfunc_)(int);
int param_;

};

void system_callback(void* p)
{
reinterpret_cast<helper*>(p)->call();
}
//上面的代码都是用于实现回调的基础部件

class foo
{
public:
foo():str_("test"){}

void fun(int x) //假如现在 对这个成员函数 回调
{
using namespace std;
cout<<str_<<':'<<x<<endl;
}
private:
std::string str_;
};

int main()
{
foo* p = new foo;
entity<foo> x(p, &foo::fun, 5);

system_callback(&x); //假设这个对调是系统产生的
delete p;
}

利用这个骨架可以写出更方便,更安全的框架
hj008 2005-05-18
  • 打赏
  • 举报
回复
别外,声名为static的成员函数是可以访问类的类员变量的
加载更多回复(8)

64,684

社区成员

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

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