IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

用C++面向对象的方式动态加载so

Vimer 2009-12-11 22:59:10 累计浏览 3,906 次
本机暂存

    这几天在写一个server,由于框架相同,仅仅是获取数据源的地方有区别,所以,研究了一下如何使用面向对象的方法来动态加载so。

    主要思想就是:

    1.通过一个函数能够获得一个基类的指针,这样在调用基类的函数的时候,就能自动调用子类的实现了。

    2.存储so对象的指针应该是外层类的一个static变量。

    详细还是看代码吧:

    1)首先定义一个公共的头文件,里面存储的基类的定义:(需要注意的就是,只要不是纯虚函数,那么就一定要有实现;还有就是析构函数需要为虚函数)

    so和主调程序都需要包含这个头文件。

    source_base.h

#ifndef _SOURCE_BASE_H_

    #define _SOURCE_BASE_H_

    #include

    using namespace std;

    class CSourceBase;

    /**

     * @brief 获取实例

     *

     * @param client new出的指针

     *

     * @return 0 succ

     * else fail

     */

    extern “C” int CreatObj(CSourceBase *& client);

    class CSourceBase

    {

     public:

     CSourceBase(){};

     virtual ~CSourceBase(){};

     public:

     virtual int GetFriends(int iUin,char *data,int &iLen,int maxLen)

     {

     return 0;

     }

    };

    #endif

    2)我们来看so的实现

    xy_source.h

#ifndef _XY_SOURCE_H_

    #define _XY_SOURCE_H_

    #include

    #include “sourcebase.h”

    using namespace std;

    class CXY_Source:public CSourceBase

    {

     public:

     CXY_Source();

     virtual ~CXY_Source();

     {}

     int GetFriends(int iUin,char *data,int &iLen,int maxLen);

    };

    #endif

    xy_source.cpp

#include “xy_source.h”

    int CreatObj(CSourceBase *& client)

    {

     client = new CXY_Source();

     return 0;

    }

    CXY_Source::CXY_Source() { }

    CXY_Source::~CXY_Source() { }

    int CXY_Source::GetFriends(int iUin,char *data,int &iLen,int maxLen)

    {

     return 0;

    }

    3)调用者的实现

    这里说明一下,因为这里想要对外封装成透明的,所以,采用了如下的方式。

    xy_client.h

#ifndef _XY_CLIENT_H_

    #define _XY_CLIENT_H_

    #include

    #include “sourcebase.h”

    using namespace std;

    typedef int (*FunPtr)(CSourceBase *& client);

    class CXY_Client

    {

     public:

     static void *SoObj;

     public:

     CXY_Client();

     virtual ~CXY_Client();

     //载入so

     int Init(const char * soname);

     int GetFriends(int iUin,char *data,int &iLen,int maxLen);

     private:

     CSourceBase *m_Client;

    };

    xy_client.cpp

#include “xy_client.h”

    void* CXY_Client::SoObj=NULL;

    CXY_Client::CXY_Client()

    {

     m_Client = NULL;

    }

    CXY_Client::~CXY_Client()

    {

     if(m_Client)

     {

     delete m_Client;

     }

    }

    int CXY_Client::Init(const char * soname)

    {

     string strSoName;

     if(soname==NULL)

     {

     strSoName = “../lib/xysource.so”;

     }

     else

     {

     strSoName = soname;

     }

     if(strSoName.size()==0)

     {

     strSoName = “../lib/xysource.so”;

     }

     if(CXY_Client::SoObj == NULL)

     {

     SoObj=dlopen((char*)strSoName.c_str(),RTLD_LAZY);

     if(SoObj==NULL)

     {

     return -1;

     }

     }

     if(m_Client==NULL)

     {

     FunPtr func;

     func = (FunPtr)dlsym(SoObj, “CreatObj”);

     int ret = (*func)(m_Client);

     if(ret)

     {

     return -2;

     }

     }

     return 0;

    }

    int CXY_Client::GetFriends(int iUin,char *data,int &iLen,int maxLen)

    {

     return m_Client->GetFriends(iUin,data,iLen,maxLen);

    }

    OK,到此为止代码就结束了,大家可能会发现我没有调用dlclose,这是因为static变量没有必要来调用,在进程结束时会自动释放句柄,当然如果需要有释放的应用场景的话,可以通过增加计数来实现。

    另外由于上面的这个实例是从项目中抠出来的,所以并不能直接编译,还望大家见谅。

    但是在这里可以下载到一个简单的可编译实例,可以用来作为实现so动态加载编程的第一步~~

    代码下载

    附:dlopen参数说明:

void *dlopen(const char *filename, int flag);

    其中flag有:RTLD_LAZY RTLD_NOW RTLD_GLOBAL,其含义分别为:

    RTLD_LAZY:在dlopen返回前,对于动态库中存在的未定义的变量(如外部变量extern,也可以是函数)不执行解析,就是不解析这个变量的地址。

    RTLD_NOW:与上面不同,他需要在dlopen返回前,解析出每个未定义变量的地址,如果解析不出来,在dlopen会返回NULL,错误为:

    : undefined symbol: xxxx…….

    RTLD_GLOBAL:它的含义是使得库中的解析的定义变量在随后的随后其它的链接库中变得可以使用。

    版权所有,转载请注明出处。http://www.vimer.cn

原图已失效

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. 如何学好C++语言 (累计阅读 10,448)
  2. Emacs配置C/C++-mode的代码智能提示和自动补全 (累计阅读 10,411)
  3. colortail,让 tail 命令绚丽起来 (累计阅读 10,259)
  4. 在C++中实现foreach循环,比for_each更简洁! (累计阅读 9,499)
  5. 几个内存相关面试题(c/c++) (累计阅读 9,445)
  6. 关于使用STL的红黑树map还是hashmap的问题 (累计阅读 8,875)
  7. 浅析C++多线程内存模型 (累计阅读 8,802)
  8. C++ 多线程编程总结 (累计阅读 8,097)
  9. 使用gdb调试运行时的程序小技巧 (累计阅读 7,208)
  10. 在C++里写一个不能被继承的类 (累计阅读 6,580)