C++ 插件实现

什么是插件

插件(Plug-In) 又称:加载项(Add-On), 外接程序(Add-In),扩展(Extension)等等, 是一种通过动态加载功能模块(即插件)来增强主程序功能的软件设计策略。通过制定标准化接口,确保插件与主程序之间的兼容性与独立性,并方便功能拓展。插件技术广泛应用于IDE开发、游戏引擎、多媒体处理等场景。

插件的基本架构

在这里插入图片描述

插件的原理

C++使用动态加载技术即运行时加载:在运行过程中通过系统调用加载,主动加载多个接口一致动态库。

  • (动态链接)通常情况:一个程序启动加载dll是在链接器确定的,并且该符号不能重复
  • 动态加载:程序在运行期主动加载或者卸载,可以有相同的符号
    可以看出来,插件实现在于规范了接口,以保证各个插件的接口统一。而动态加载则保证了插件可以正常加载到程序中。
    从依赖的建立来看,动态链接依赖在链接的时候建立的。一旦exe发布后,这个依赖就存在而不可以打破。动态加载则是在exe运行加载时建立的即exe系统调用加载动态库的时候

动态库的加载时机

  • 动态链接:在exe启动的时候加载
  • 延时加载:在程序运行过程中第一次用到依赖库导出的符号再加载
    • MVSC:/DDLAYLOAD: demo.dll (符号重载决议)在调用函数和
  • 动态加载: 程序员自动控制加载
    • 系统API

实现一个简单的插件

  • plugin
//定义插件的公共接口 
class IPlugin {
    public:
        virtual void initialize() = 0;
        virtual void execute() = 0;
        virtual void cleanup() = 0; 
};
  • Helloplugin
#include <iostream>
class HelloPlugin : public IPlugin {
public:
    void initialize() override {
        std::cout << "HelloPlugin initialized." << std::endl;
    }

    void execute() override {
        std::cout << "Hello from HelloPlugin!" << std::endl;
    }

    void cleanup() override {
        std::cout << "HelloPlugin cleaned up." << std::endl;
    }
};

extern "C" IPlugin* create() {
    return new HelloPlugin();
}

extern "C" void destroy(IPlugin* plugin) {
    delete plugin;
}
  • Pluginmanager
#include "IPlugin.h"
#include <string>
#include <vector>
#include <dlfcn.h> // Linux下的动态链接库头文件

class PluginManager {
public:
    void loadPlugin(const std::string& path) {
        void* handle = dlopen(path.c_str(), RTLD_LAZY);
        if (!handle) {
            std::cerr << "Cannot load plugin: " << dlerror() << std::endl;
            return;
        }

        // 获取创建插件的函数
        IPlugin* (*create)();
        create = (IPlugin* (*)())dlsym(handle, "create");
        if (!create) {
            std::cerr << "Cannot load create function: " << dlerror() << std::endl;
            return;
        }

        // 创建插件实例
        IPlugin* plugin = create();
        plugin->initialize();
        plugins.push_back(std::make_pair(plugin, handle));
    }

    void executePlugins() {
        for (auto& p : plugins) {
            p.first->execute();
        }
    }

    void unloadPlugins() {
        for (auto& p : plugins) {
            p.first->cleanup();
            dlclose(p.second);
            delete p.first;
        }
        plugins.clear();
    }

private:
    std::vector<std::pair<IPlugin*, void*>> plugins;
};
  • application
#include "PluginManager.h"

int main() {
    PluginManager manager;
    manager.loadPlugin("./HelloPlugin.so");
    manager.executePlugins();
    manager.unloadPlugins();

    return 0;
}

从上面可以看出来插件的设计主要关注以下几点

  • 动态库加载(跨平台)
  • 内存管理
  • 插件接口如何设计
  • 插件生命周期管理
  • 插件间通信
  • 各个插件的依赖项版本不一致的管理
  • 各个插件的公共库管理

插件系统的拓展

  • 应用层
    • 热插拔(替换新插件)
    • 自动文件检测 (拖入新插件,插件本身的含义)
  • 插件接口
    • 函数注册版 + 配置文件
      • rpc服务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值