在上一篇《 Qt动态库加载之 QLibrary 》 一文中,和大家分享了Qt 编译和调用C动态库的方法。在动态库中,我们使用了函数指针,借用函数指针实现C语言中的“多态”;其次,在库中我们实现固定的算法和业务,将可能会更改的部分以接口的形式抛出,用户在调用时也可以更加灵活,在一定程度上起到了解耦的作用。
#ifndef CBB_MYLOG_H
#define CBB_MYLOG_H
#if defined(CBB_LIBRARY)
# define _API extern "C" __declspec(dllexport)
#else
# define _API extern "C" __declspec(dllimport)
#endif
typedef void (*cbb_func)(void* ref,int len);
typedef struct cbb_data
{
cbb_func func;
void* ref;
int len;
}cbb_t,*p_cbb;
enum log_level{
LEVEL1,
LEVEL2,
LEVEL3
};
_API void cbb_mylog(p_cbb pb,log_level level,char* f,...);
#endif // CBB_MYLOG_H
#include "cbb_mylog.h"
#include <stdio.h>
#include <stdarg.h>
void cbb_mylog(p_cbb pb, log_level level, char *f,...)
{
if ( nullptr != pb ) pb->func(pb->ref,pb->len); # 回调函数
char buf[4000] = {0};
va_list args;
va_start(args, f);
vsprintf(buf, f,args);
va_end(args);
printf("%s\n",buf);
}
用户在调用C动态库时,可以实现 自己的 typedef void (*cbb_func)(void* ref,int len);
#include <QCoreApplication>
#include <QLibrary>
#include <QDebug>
typedef void (*cbb_func)(void* ref,int len);
typedef struct cbb_data
{
cbb_func func;
void* ref;
int len;
}cbb_t,*p_cbb;
enum log_level{
LEVEL1,
LEVEL2,
LEVEL3
};
typedef void (*cb_func)(p_cbb pb,log_level level,char* f,...);
typedef int (*padd)(int x,int y);
void show_help(void* ref,int len){
printf("%s %d show_help \n",__FILE__,__LINE__);
}
void show_help2(void* ref,int len){
printf("%s %d show_help2 \n",__FILE__,__LINE__);
}
void show_help3(void* ref,int len){
printf("%s %d show_help3 \n",__FILE__,__LINE__);
}
// ...
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString library_path = QCoreApplication::applicationDirPath() + "/cbb_frame.dll";
QLibrary* L = new QLibrary(library_path);
if( nullptr == L) return -1;
if(! L->load()){
qDebug() << "[error:]" << L->errorString();
delete L;
L = NULL;
}
// 如下,均调用动态库中的cbb_mylog 方法,但由于我们传入的函数指针不同,
// 程序在运行时,产生了不同的运行状态和结果,实现了C语言的“多态”
// ![1]
cb_func myprintf = (cb_func)L->resolve("cbb_mylog");
cbb_t cbb = {show_help,NULL,0};
myprintf(&cbb,LEVEL1,"%s","show_help");
// ![2]
cbb_t cbb2 = {show_help2,NULL,0};
myprintf(&cbb2,LEVEL1,"%s","show_help2");
// ![3]
cbb_t cbb3 = {show_help3,NULL,0};
myprintf(&cbb3,LEVEL1,"%s","show_help3");
L->unload();
return a.exec();
}