QT4编程之 - 将类成员函数用做C回调函数

 QT4编程之 - 将类成员函数用做C回调函数
2010-05-18 20:42:00
标签: 编程  函数  休闲  职场  QT4

提出问题: 
回调函数是基于C语言编程技术的,不是针对C++的,程序员可以将一个C函数直接作为回调函数,但是如果试图直接使用C++的成员函数作为回调函数将发生错误,甚至编译就不能通过。
 

分析原因:
普通的C++成员函数都隐含了一个传递函数作为参数,亦即“this”指针,C++通过传递一个指向自身的指针给其成员函数从而实现程序函数可以访问C++的数据成员。这也可以理解为什么C++类的多个实例可以共享成员函数但是确有不同的数据成员。由于this指针的作用,使得将一个CALLBACK型的成员函数作为回调函数安装时就会因为隐含的this指针使得函数参数个数不匹配,从而导致回调函数安装失败。

解决方案:
一、不使用成员函数,直接使用普通C函数,为了实现在C函数中可以访问类的成员变量,可以使用友元操作符(friend),在C++中将该C函数说明为类的友元即可。这种处理机制与普通的C编程中使用回调函数一样。

二、使用静态成员函数,静态成员函数不使用this指针作为隐含参数,这样就可以作为回调函数了。静态成员函数具有两大特点:其一,可以在没有类实例的情况下使用;其二,只能访问静态成员变量和静态成员函数,不能访问非静态成员变量和非静态成员函数。由于在C++中使用类成员函数作为回调函数的目的就是为了访问所有的成员变量和成员函数,如果作不到这一点将不具有实际意义。我们通过使用静态成员函数对非静态成员函数包装的办法来解决问题。类实例可以通过附加参数或全局变量的方式的方式传递到静态成员函数中。分别举例如下:在myinc.h中定义一个函数指针类型,如下: 
 

  
  
  1.  
  2. typedef int __stdcall PACKET_DISPATCH_ROUTINE (
  3. int nChID,
  4. unsigned char *pPacket,
  5. unsigned long nLength,
  6. void *Context);

 

1、参数传递的方式

  
  
  1. #include <myinc.h>
  2. class TClassA
  3. {
  4. public:
  5. void Display(const char* text)
  6. {
  7. cout << text << endl;
  8. };
  9. static PACKET_DISPATCH_ROUTINE OnPacketRecieved; //声明一个函数指针类型的变量OnPacketRecieved
  10. // more....
  11. };
  12. // 静态包装函数,能够调用成员函数Display(),本身做为回调函数来使用
  13. int PacketReceived::OnPacketRecieved(int nChID, unsigned char *pPacket, unsigned long nLength, void *Context)
  14. {
  15. // 显式类型转换
  16. TClassA* mySelf = (TClassA*) pt2Object;
  17. // 调用普通成员函数
  18. mySelf->Display(string);
  19. }
  20. // 回调函数的宿主,在这里回调用函数被使用
  21. void DoItA(void* pt2Object, int (*pt2Function)(int nChID, unsigned char *pPacket, unsigned long nLength, void *Context))
  22. {
  23. // 使用回调函数
  24. pt2Function(......);
  25. }
  26. // 执行示例
  27. void Callback_Using_Argument()
  28. {
  29. TClassA objA;
  30. DoItA((void*) &objA, this->OnPacketRecieved);
  31. }


2、全局变量的方式
 

  
  
  1. #include <iostream.h>
  2. void* pt2Object; // 全局变量,可以指向任意对象
  3. class TClassB
  4. {
  5. public:
  6. void Display(const char* text) { cout << text << endl; };
  7. static void Wrapper_To_Call_Display(char* text);
  8. };
  9. // 静态的包装函数
  10. void TClassB::Wrapper_To_Call_Display(char* string)
  11. {
  12. //需要保证全局变量值的正确性
  13. TClassB* mySelf = (TClassB*) pt2Object;
  14. mySelf->Display(string);
  15. }
  16. // 回调用函数的宿主,在这里回调用函数被使用
  17. void DoItB(void (*pt2Function)(char* text))
  18. {
  19. pt2Function("hi, i'm calling back using a global ;-)"); // make callback
  20. }
  21. // 执行示例
  22. void Callback_Using_Global()
  23. {
  24. TClassB objB;
  25. pt2Object = (void*) &objB;
  26. DoItB(TClassB::Wrapper_To_Call_Display);
  27. }

注意:通过上面两种方法的比较可以看出,第2种方法中静态包装函数可以和普通成员函数保持签名一致,当回调函数的宿主接口不能改变时,这种方法特别有用。但因为使用了全局变量,也不是一个好的设计。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Qt,函数可以作为回调函数使用。回调函数是在特定事件发生时被用的函数。 要将一个函数作为回调函数,首先需要定义一个函数指针类型,然后将函数指针作为参数传递给需要使用回调函数的函数。 以下是一个示例,演示了如何在Qt使用类函数作为回调函数: ```cpp #include <QObject> #include <QDebug> // 定义回调函数的函数指针类型 typedef void (MyClass::*CallbackFunction)(int); class MyClass : public QObject { Q_OBJECT public: MyClass(QObject *parent = nullptr) : QObject(parent) {} // 回调函数 void callback(int value) { qDebug() << "Callback called with value:" << value; } // 接受回调函数作为参数的函数 void doSomething(CallbackFunction callback) { // 在特定事件发生时回调函数 int value = 42; (this->*callback)(value); } }; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); MyClass obj; CallbackFunction func = &MyClass::callback; // 将类成员函数作为回调函数传递给 doSomething 函数 obj.doSomething(func); return app.exec(); } ``` 在上述示例,`MyClass` 是一个继承自 `QObject` 的自定义类。该类拥有一个成员函数 `callback`,它是我们要作为回调函数使用的函数。`doSomething` 函数接受一个回调函数作为参数,并在特定事件发生时用该回调函数。 在 `main` 函数,我们创建了一个 `MyClass` 对象 `obj`,并将类成员函数 `callback` 的函数指针赋值给变量 `func`。然后,我们将 `func` 作为参数传递给 `doSomething` 函数,从而将 `callback` 函数作为回调函数使用。 当运行程序时,将输出 `"Callback called with value: 42"`,表示回调函数成功被用。 请注意,使用类函数作为回调函数时,需要使用指向类成员函数的指针,并使用 `this->*callback` 语法来用该函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值