Load the so method dynamically with C++ object oriented method

  • 2020-05-10 18:36:12
  • OfStack

These days I was writing an server. Since the framework is the same, there is only a difference in where I get the data source. Therefore, I studied how to use an object-oriented method to dynamically load so.

The main idea is:

1. A pointer to a base class can be obtained through a function, so that the implementation of the subclass can be automatically called when the function of the base class is called.

2. The pointer to the so object should be one of the static variables of the outer class.

See the code for details:

1) first, define a common header file with the definition of the base class stored in it :(note that as long as it is not a pure virtual function, there must be an implementation; And the destructor needs to be virtual.)

Both so and the host need to include this header file.

source_base.h


#ifndef _SOURCE_BASE_H_
#define _SOURCE_BASE_H_
#include <iostream>
using namespace std;
class CSourceBase;
/** 
 * @brief   For instance 
 * 
 * @param  client    new The pointer 
 * 
 * @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) let's look at the implementation of so

xy_source.h


#ifndef _XY_SOURCE_H_
#define _XY_SOURCE_H_
#include <iostream>
#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) implementation of the caller

Note 1 here, because it is intended to be transparent, the following approach is used.

xy_client.h


#ifndef _XY_CLIENT_H_
#define _XY_CLIENT_H_
#include <iostream>
#include  " sourcebase.h " 
using namespace std;
typedef int (*FunPtr)(CSourceBase *& client);
class CXY_Client
{
  public:
    static void *SoObj;
  public:
    CXY_Client();
    virtual ~CXY_Client();
    // load 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, that's the end of the code, you might notice that I didn't call dlclose, because static doesn't have to be called, it will automatically release the handle at the end of the process, of course if you need to have a release of the application scenario, you can do that by increasing the count.

In addition, since the above example was extracted from the project, it cannot be directly compiled, please forgive me.

But here you can download a simple compilable example that can be used as the first step in implementing so dynamic loading programming ~~


Related articles: