• 15215阅读
  • 8回复

Qt中动态链接库的使用 [复制链接]

上一主题 下一主题
离线kezou
 
只看楼主 倒序阅读 楼主  发表于: 2008-12-19
— 本帖被 XChinux 设置为精华(2008-12-19) —
昨天一个同事说要把一个类做成DLL的形式,但这个类不是从QWidget继承。 研究了一下,发现Qt提供了一个类QPluginLoader可以加载动态链接库。能把一个普通的类编译生成DLL,通过QPluginLoader使用它。

写一个例子说明吧:
工程A中,使用了这样一个类,专门用来让算所得税;
Tax.h
class  Tax
{
  float incomeTax(int income);
};

Tax.cpp
Tax::incomeTax(int income)
{
float res=(income-1600)*0.5;
return res;
}

main.cpp
Int main()
{
Tax taxobject;
taxObject. incomeTax(2200);
............
}
编译后部署到机器上.

如果计税方式变了,则incomeTax()必须改写了;
Tax::incomeTax(int income)
{
float res=(income-2000)*0.3;
return res;
}


头文件没有变,只是修改了计税方式,工程A必须重新编译,然后重新部署; 如果工程A很大或部署的机器很多,代价就大了.
如果让Tax类,单独编译成动态链接库,再把Tax中的要被使用的接口写在另一个头文件中,供工程A使用;每次计税方式变了,只需修改Tax类,然后重新编译生成动态链接库,然后替换工程A中的相应的动态链接库.而工程A不用重新编译即可使用新的计税方式.

新建一工程B,专门用来把Tax类做成动态连接库的形式:

//首先定义接口(只要一个头文件即可)
Tax.h
class Tax
{
    virtual float incomeTax(int income);
};
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(Tax,"TaxDLL/1.0");  //这个宏用声明接口
QT_END_NAMESPACE


然后从写一个具体业务类,继承上面的接口和QObject,实现接口中定义的方法
TaxPlugin.h
class  TaxPlugin:public QObject,Tax
{
    Q_OBJECT
    Q_INTERFACES(Tax)         
public:
  float incomeTax(int income);
};

TaxPlugin.cpp
TaxPlugin::incomeTax(int income)
{
float res=(income-1600)*0.5;
return res;
}
Q_EXPORT_PLUGIN2(Tax, TaxPlugin);    //这个宏用来导出动态链接库

编译工程B,生成Tax.dll.


把工程Tax.dll和头文件Tax.h,拷到工程A中,供工程A使用.
工程A中
int main()
{
Tax *taxObject;
QPluginLoader pluginLoader("Tax.dll");
QObject *plugin = pluginLoader.instance();
taxObject= qobject_cast<Tax *>(plugin);
taxObject->incomeTax(2100);
}
如果税率变了,只要修改工程B中的类,然后重新编译生成Tax.dll,替换工程A中原来的库.而工程A不必重新编译即可使用新的计税方式.


现在有些软件有自动升级功能,有些就是下载新的DLL文件,替换原来的动态链接库.
MFC好象也有类似机制

Qt还有一种方式,就是把一个QWidget子类,编译成动态链接库.然后根据动态链接库创建一个对象,返回QWidget子针,如果你的类不是QWidget的子类,就不能用这种方法了

QLibrary也是用来加载动态链接库,但它创建出来返回的是某个"方法的指针"(不需要头文件),而QPluginLoader创建返回的是"对象的指针"(对象中有哪些方法可调用,就要头文件说了,所以上面的例子中,需要提供一个接口头文件)

[ 此贴被kezou在2008-12-19 13:55重新编辑 ]
离线wvins
只看该作者 1楼 发表于: 2008-12-19

Tax.h
class Tax
{
    virtual float incomeTax(int income);
};
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(Tax,"TaxDLL/1.0");  //这个宏用声明接口
QT_END_NAMESPACE


我记得这个宏的第二个参数由四部分组成,
    公司,
    主程序名称,
    DLL名称,
    DLL版本

Q_DECLARE_INTERFACE(Tax,"TaxDLL/1.0");  //这个宏用声明接口
你这里只传了两个,会不会有什么问题?
离线kezou
只看该作者 2楼 发表于: 2008-12-19
Q_DECLARE_INTERFACE ( ClassName, Identifier )
This macro associates the given Identifier (a string literal) to the interface class called ClassName. The Identifier must be unique.
只有两个参数哈.

如果要加公司名和主程序名,用"."隔开写
如 company.program.Dll/1.0 
但试过了,不写也行.
离线earctan

只看该作者 3楼 发表于: 2008-12-19
领教了。
有个问题,用VC写成的动态链接库,能不能导出Qt写的类?
还是只能用这种方法
离线wvins
只看该作者 4楼 发表于: 2008-12-19
谢谢,
我暂时还没做到模块化,所以没有去试。


VC写的动态链接库是通过QLibrary调用的。
离线6楼男生
只看该作者 5楼 发表于: 2008-12-19
鼓掌加油
小可  不错哦
离线yiyaaixuexi

只看该作者 6楼 发表于: 2011-07-25
VC写的动态链接库是通过QLibrary调用的。
离线guang0908090
只看该作者 7楼 发表于: 2011-07-27
不错喔
快乐每一天
离线y286572046

只看该作者 8楼 发表于: 2011-07-29
你写的这个东西,我最近尝试了很多次,可惜编译出现一堆错,你自己编译通?
快速回复
限100 字节
 
上一个 下一个