• C++:实现委托机制


    C++ 委托机制

    在GUI编程或者基于事件开发的项目中,经常需要使用回调函数. 为了处理这类回调事件, C# 特别提供了关键字delegate来实现.

    函数指针回调做法

    在传统的C++开发过程中, 为了实现函数回调,一般的做法是将 C++ 的函数指针传给管理者.当有事件触发时,再执行该回调函数.

    基于函数指针的回调方式有一下缺点:

    • 对萌新不友好, 上手困难
    • 函数指针操作并不安全,无法在编译阶段检测来

    C++11 新特性

    为了解决此类问题, C++11 从boost库中借鉴了新特性 functional, 以此为容器存储函数指针,从而优雅的实现回调机制

    案例演示:

    • 存储自由函数
    • 存储lambda表达式
    • 存储std::bind 结果 (非常重要)
    • 存储类成员方法和类实例
    • 存储类成员方法和类实例指针
    • 存储结构体方法
    1. #pragma once
    2. #include
    3. #include
    4. void print_num(int i);
    5. inline void print_num(int i)
    6. {
    7. std::cout << i << '\n';
    8. }
    9. struct PrintNum {
    10. void operator()(int i) const
    11. {
    12. std::cout << i << '\n';
    13. }
    14. };
    15. struct Foo {
    16. Foo(int num) : num_(num) {}
    17. void print_add(int i) const { std::cout << num_ + i << '\n'; }
    18. int num_;
    19. };
    20. void main();
    21. inline void main()
    22. {
    23. // store a free function
    24. std::function<void(int)> f_display = print_num;
    25. f_display(-9);
    26. // store a lambda
    27. std::function<void()> f_display_42 = []() { print_num(42); };
    28. f_display_42();
    29. //store the result of a call to std::bind
    30. std::function<void()> f_display_31337 = std::bind(print_num, 31337);
    31. f_display_31337();
    32. // //store a call to a member function
    33. //std::function f_add_display = &Foo::print_add;
    34. const Foo foo(314159);
    35. //f_add_display(foo, 1);
    36. //store a call to a data member accessor
    37. //std::function f_num = &Foo::num_;
    38. //std::cout << "num_: " << f_num(foo) << '\n';
    39. // store a call to a member function and object
    40. using std::placeholders::_1;
    41. std::function<void(int)> f_add_display2 = std::bind(&Foo::print_add, foo, _1);
    42. f_add_display2(2);
    43. // store a call to a member function and object ptr
    44. std::function<void(int)> f_add_display3 = std::bind(&Foo::print_add, &foo, _1);
    45. f_add_display3(3);
    46. // store a call to a function object
    47. std::function<void(int)> f_display_obj = PrintNum();
    48. f_display_obj(18);
    49. }

    委托机制实现

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. class IObj
    7. {
    8. public:
    9. virtual int callback(string t_data) = 0;
    10. };
    11. class AppleObj : public IObj
    12. {
    13. public:
    14. virtual int callback(string t_data) final
    15. {
    16. cout << "this is appleobj : " << endl;
    17. return 0;
    18. }
    19. };
    20. class BananaObj : public IObj
    21. {
    22. public:
    23. virtual int callback(string t_data) final
    24. {
    25. cout << "this is banana object: " << endl;
    26. return 1;
    27. }
    28. };
    29. class DeleManager
    30. {
    31. public:
    32. DeleManager() {};
    33. ~DeleManager() {};
    34. void addObj(function<int(string)> t_dele)
    35. {
    36. _dele_list.push_back(t_dele);
    37. }
    38. void notify(string t_msg)
    39. {
    40. if (_dele_list.empty())
    41. {
    42. cout << "list is empty " << endl;
    43. return;
    44. }
    45. for (auto itor : _dele_list)
    46. {
    47. itor(t_msg);
    48. }
    49. }
    50. private:
    51. vector int(string)>> _dele_list;
    52. };
    53. void main()
    54. {
    55. DeleManager i_manager;
    56. AppleObj i_apple;
    57. BananaObj i_banana;
    58. using std::placeholders::_1;
    59. std::function<int(string)> i_dele_apple = std::bind(&AppleObj::callback, i_apple, _1);
    60. i_manager.addObj(i_dele_apple);
    61. std::function<int(string)> i_dele_banana = std::bind(&BananaObj::callback, i_banana, _1);
    62. i_manager.addObj(i_dele_banana);
    63. i_manager.notify("happy middle september day");
    64. }

    windows消息回调

    在windows GUI 开发过程中, 一般通过 postmessage 来完成消息回调,触发GUI执行对应的操作. 这种方式简单易行,对萌新友好,且具备跨线程操作的功能. 但是postmessage 也有自身的缺陷:

    • 过渡依赖windows消息机制
    • 回调传参可定制程度低

    总结

    为了解决GUI 跨线程操作界面的导致主线程崩溃的情况, C++ 11 终于推出了自己的thread 类
    thread 类提供detach() 的方法, 让worker线程也具备了操作GUI的能力.
    在GUI开发中, 通过使用functionthread等C++ 11 新特性,能够更便捷的开发出高质量的程序, 同时回避开发过程中的问题。

    转:https://www.jianshu.com/p/c2c34014b739

  • 相关阅读:
    商城免费搭建之java商城 java电子商务Spring Cloud+Spring Boot+mybatis+MQ+VR全景+b2b2c
    Jenkins部署详细教程
    Spring之美- IOC和AOP
    Day10:for循环结构的使用详解
    记录本地Nginx发布vue项目
    SQL报错:Out of range value for column ‘fileLength‘ at row 1
    二进制基础
    DA3 网站的第10位用户信息读取
    RabbitMQ图解
    javaweb狂神版(待更新)
  • 原文地址:https://blog.csdn.net/m0_66030415/article/details/126391160