zoukankan      html  css  js  c++  java
  • 将接受子类指针的回调函数统一管理

    假设一个场景:收到网络协议的时候自动调用对应回调函数,回调函数的对象是协议参数。当我们处理不同的协议的时候需要不同的参数,那么我们只能让具体的参数继承自一个基类A。

    这样一来我们就只能这样写回调函数

    void fun(A* p)
    {
        具体类型* param = (具体类型*)p;
        ……
    }
    

    这样一来回调函数的内部一般第一句话就是强转类型(或者用dynamic_cast也可以),与逻辑无关。

    如果遇到了我这样有强迫症的人会不爽,怎么解决掉这个问题?

    //假设已经有B类继承自A类
    class Manager { public: using CallbackFunction = std::function<void(A*)>; template <class T> void Register(std::string key, std::function<void(T*)> callback) { static_assert(std::is_base_of<A, T>::value); _functions.insert(std::make_pair(key, [=](A* p) { callback((T*)p); })); } void Trigger(std::string key, A* param) { auto it = _functions.find(key); if (it != _functions.end()) it->second(param); } private: std::map<std::string, CallbackFunction> _functions; }; int main() { Manager m; auto cb = [](B* p) { std::cout << "in cb" << std::endl; }; m.Register<B>("B", cb); B* temp = new B; m.Trigger("B", temp); delete temp; return 0; }

    因为使用了static_assert所以需要在编译选项中加入/std:c++latest

    先讲讲static_assert,static_assert是静态断言,可以在编译期间对一些常量表达式之类的计算来实现断言,没有运行时期开销。

    std::is_base_of定义于<type_traits>中,功能是判断一个类是否为一个类的子类,具体的判断方法是SFINA(匹配失败不是错误),用模板的方法判断是否具有继承关系。

    实现这个功能的核心思路就是利用模板成员函数接受子类对象类型的回调函数,然后套上一个lambda,在lambda中强转基类类型然后调用接受子类对象类型的回调函数。

    不过说实话,上面这段代码学习意义大于实际意义,因为一般情况下这种回调函数框架都是由代码生成器生成的(什么你告诉我你手写?再见。),完全可以把强转这个步骤放在生成器里面,一步到位。

    而这种做法会有一层lambda的间接调用(或许编译器能够聪明到理解含义并且优化成一个强转),效率可能会略低一些。

  • 相关阅读:
    mapreduce 本地调试需要注意的问题
    socket-----爬虫&&文件传输
    多个地点ping服务器
    linux grep命令详解
    关于真多核和加多核&线程由哪几部分组成
    内存溢出和内存泄漏
    指针和引用的区别
    Doxygen的使用,配置及实例
    【转】doxygen+graphviz生成工程中的类继承树及函数调用图
    转载--void指针(void *的用法)
  • 原文地址:https://www.cnblogs.com/reskai/p/8045348.html
Copyright © 2011-2022 走看看