1. 程式人生 > >C++載入動態庫的形式來實現封裝

C++載入動態庫的形式來實現封裝

目錄結構

└── test
    ├── CMakeLists.txt
    ├── base.h                            //設定介面
    ├── drive.cpp                        //具體實現
    └── main.cpp                        //test

CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
project (test)

set(CMAKE_CXX_STANDARD 11)

include_directories(./)

add_library(drive SHARED drive.cpp) #將實現新增為動態庫
add_executable(test main.cpp) #將test生成可執行
target_link_libraries(test ${CMAKE_DL_LIBS}) #連結dl庫

base.h

#ifndef BASE_H
#define BASE_H
#include <iostream>
#include <memory>
#include <dlfcn.h>

using namespace std;

 //巨集用在drive.cpp中生成產生子類物件的函式
#define USE_MAPFUSION_PLUGIN(C) extern "C"{\
    shared_ptr<base> createInstance(){return shared_ptr<base>(new C());}}     


class base;
typedef shared_ptr<base> (*funcCreatClass)();

class base {
public:
    virtual void print() {cout << "base" << endl;}

    static shared_ptr<base> create(const string& plugin) {
        int realFlags = RTLD_LAZY|RTLD_GLOBAL;
        void* handle = dlopen(plugin.c_str(), realFlags);//開啟庫
        if (!handle) {
            const char* err = dlerror();
            cerr << "Can not open file " << plugin << "since " << err << endl;
            return shared_ptr<base>();
        }
        funcCreatClass createFunc = (funcCreatClass)dlsym(handle, "createInstance");  //載入庫中生成子類物件的函式
        if(!createFunc) return shared_ptr<base>();
        else return createFunc();
    }
};
#endif // BASE_H

drive.cpp

#include "base.h"

using namespace std;

class drive : public base {
public:
    virtual void print() {cout << "drive" << endl;}
};

USE_MAPFUSION_PLUGIN(drive)                                            //展開base.h中的巨集來生成產生子類物件的函式

main.cpp

#include "base.h"

using namespace std;

int main(int argc, char *argv[])
{
    shared_ptr<base> a = base::create("libdrive.so");
    a->print();
}

執行結果

$ mkdir build
$ cd build
$ camke ..
$ make 
$ ./test
///輸出
//drive