Linux下C++编程使用动态链接库
在《Linux下C编程使用动态链接库》一文中已了解到了C语言里如何使用共享库SO了,但在C++里可全是类,该如何实现呢?C语言中的操作只能导出全局函数,并不能导出类的方法,故而需要设计相关的全局函数来封装一层。这里用到了“类工厂函数”的设计模式,定义一个抽象类(含有纯虚函数)的头文件,然后在SO源文件和使用的源文件里均包含该头文件,在SO里继承并实现抽象类里的纯虚函数。具体看下面的实例,头文件里创建多边形类(作为接口),而在SO继承它并实现三角形类,并且设计了全局的创建和销毁类对象的函数:
polygon.hpp(纯虚父类,多边形类):
#ifndef POLYGON_HPP
#define POLYGON_HPP
class polygon {
protected:
double _side_length;
public:
polygon() : _side_length(0) {}
virtual ~polygon() {}
void set_side_length(double side_length) {
_side_length = side_length;
}
virtual double area() const = 0;
};
typedef polygon* create_t();
typedef void destroy_t(polygon*);
#endif
triangle.cpp(三角形类,继承多边形类,实现其纯虚函数):
#include "polygon.hpp"
#include <math.h>
class triangle : public polygon {
public:
virtual double area() const {
return _side_length * _side_length * sqrt(3) / 2;
}
};
extern "C" polygon* create() {
return new triangle;
}
extern "C" void destroy(polygon* p) {
delete p;
}
cppso_exam.cpp:
#include "polygon.hpp"
#include <iostream>
#include <dlfcn.h>
using namespace std;
int main()
{
void * triangle_handle = dlopen("./triangle.so", RTLD_LAZY);
if (!triangle_handle) {
cerr << "dlopen failed: " << dlerror() << '\n';
return -1;
}
create_t * create_triangle = (create_t *)dlsym(triangle_handle, "create");
const char * dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol 'create' : " << dlsym_error << '\n';
return -1;
}
destroy_t * destroy_triangle = (destroy_t *)dlsym(triangle_handle, "destroy");
dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol 'destroy' : " << dlsym_error << '\n';
return -1;
}
polygon * poly = create_triangle();
poly->set_side_length(8);
cout << "The area is : " << poly->area() << '\n';
destroy_triangle(poly);
dlclose(triangle_handle);
return 0;
}
Makefile:
all:
g++ -o triangle.so -shared -fPIC triangle.cpp
g++ -rdynamic -o cppso cppso_exam.cpp -ldl
clean:
rm -rf triangle.so cppso
相应的源码文件目录树如下:
/home/xinu/xinu/c_cpp/cpp_so_example/
├── cppso_exam.cpp
├── Makefile
├── polygon.hpp
└── triangle.cpp
我们在实现SO的triangle.cpp文件里看到了extern “C”,主要是为了处理Name Mangling的问题,即在C语言里函数名对应的符号名仍是函数名,而在C++里要支持函数重载,函数名对应的符号名则是函数名再加上参数名等组成,加上extern “C”是避免C++代码里找不到C函数(名字被改了),后期再详细说明该问题。
至此,我们了解了在类中进行共享库的处理方法。