You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C++98环境下替换boost::function与boost::bind的技术问询

替代Boost.Function/Boost.Bind实现C++98下的成员函数存储

刚好解决过类似的场景!在C++98没有std::function的限制下,我们可以自己实现一个轻量级的包装器,用多态+模板来模拟Boost的功能,完美替换你当前的代码,具体步骤如下:

1. 定义统一的可调用抽象接口

首先我们需要一个基类,提供统一的调用入口,这样向量就能存储不同子类的实例(利用多态的类型擦除特性):

class VoidCallable {
public:
    virtual ~VoidCallable() {} // 必须声明虚析构,保证子类能正确析构
    virtual void operator()() = 0; // 纯虚函数,定义调用行为
};

2. 模板子类包装成员函数与实例

接下来写一个模板类,继承上面的基类,用来保存特定类的成员函数指针和实例指针:

template <typename T>
class MemberFuncWrapper : public VoidCallable {
public:
    // 构造函数传入成员函数和实例指针
    MemberFuncWrapper(void (T::*func)(), T* instance)
        : m_memberFunc(func), m_instance(instance) {}

    // 重载()运算符,调用对应的成员函数
    virtual void operator()() {
        (m_instance->*m_memberFunc)();
    }

private:
    void (T::*m_memberFunc)(); // 成员函数指针
    T* m_instance;             // 类实例指针
};

3. 修改App类的实现

现在把原来的boost::function<void()>向量换成我们的VoidCallable*向量,同时调整AddLoopFunc来创建包装器实例:

#include <vector>

class App { 
public: 
    App() {} 

    template<class T> 
    static void AddLoopFunc(void (T::*func)(), T* instance) { 
        // 创建包装器实例并加入向量
        loop_funcs.push_back(new MemberFuncWrapper<T>(func, instance));
    } 

    // 新增:遍历调用所有循环函数
    static void RunLoop() {
        for (size_t i = 0; i < loop_funcs.size(); ++i) {
            (*loop_funcs[i])(); // 调用每个包装器的()运算符
        }
    }

    // 新增:清理内存,避免泄漏
    static void Cleanup() {
        for (size_t i = 0; i < loop_funcs.size(); ++i) {
            delete loop_funcs[i];
        }
        loop_funcs.clear();
    }

    static std::vector<VoidCallable*> loop_funcs; 
}; 

// 静态成员变量初始化
std::vector<VoidCallable*> App::loop_funcs;

4. 调用方式完全不变

你原来的调用代码不需要任何修改,直接用就行:

class MyClass {
public:
    void Loop() {
        // 你的循环逻辑代码
    }
};

// 添加循环函数
MyClass myObj;
App::AddLoopFunc(&MyClass::Loop, &myObj);

// 运行所有循环函数
App::RunLoop();

// 程序结束时记得清理内存
App::Cleanup();

关键注意事项

  • 内存管理:因为我们用new创建了包装器实例,必须在合适的时机调用App::Cleanup()来释放内存,否则会造成内存泄漏。如果想避免手动管理,C++98里可以用std::auto_ptr,但向量存储auto_ptr时要注意拷贝所有权转移的问题,所以手动清理是最稳妥的方式。
  • 线程安全:如果是多线程环境,访问loop_funcs时需要加锁,这和你原来用Boost的版本要求一致。
  • 兼容性:完全符合C++98标准,不需要任何第三方库,完美替换原来的boost::bindboost::function用法。

这个实现的核心思路和Boost.Function底层原理一致,都是用多态来实现类型擦除,把不同类型的成员函数统一成一个可调用的接口。

内容的提问来源于stack exchange,提问作者aquawicket

火山引擎 最新活动