在 Qt 中访问 DLL 的 C++ class 成员函数
Accessing C++ class member functions of a DLL in Qt
我能够在 Qt main.cpp 中创建 class 的实例,但我的应用程序在尝试访问 DLL 的 class 成员函数时崩溃。
我该怎么做?
如果这是我的dll.h
#ifndef DIVFIXTURE_H
#define DIVFIXTURE_H
#include<QObject>
#include<QVariant>
class __declspec(dllexport) DivFixture : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE DivFixture();
Q_INVOKABLE void setNumerator(QVariant num);
Q_INVOKABLE void setDenominator(QVariant denom);
Q_INVOKABLE QVariant quotient();
private:
double numerator, denominator;
};
#endif
这是我的dll.cpp
#include "testfixture.h"
DivFixture::DivFixture(){}
void DivFixture::setNumerator(QVariant num)
{
numerator=num.toDouble();
}
void DivFixture::setDenominator(QVariant denom)
{
denominator=denom.toDouble();
}
QVariant DivFixture::quotient()
{
QVariant ret;
ret=numerator/denominator;
return ret;
}
//non-class function to return pointer to class
extern "C" __declspec(dllexport) DivFixture* create()
{
return new DivFixture();
}
这是我正在导入 DLL 库的 Qt 应用程序的 main.cpp
QLibrary library(("C:\somepath\testFixture.dll");
if (!library.load())
qDebug() << library.errorString() << endl;
if (library.load())
qDebug() << "library loaded" << endl;
DivFixture *r1=NULL;
typedef DivFixture* (*MyPrototype)();
auto myFunction = (MyPrototype)library.resolve("create");
qDebug()<<myFunction;
if (myFunction)
r1=Function(); // able to create instance of DivFixture
r1->quotient(); //I'm not able to access class member function
为什么我无法使用 class 实例访问 class 成员函数 quotient()
?程序在这一行崩溃 r1->quotient();
。我可以创建 class DivFixture
的原型来访问其成员函数,而不是像 typedef DivFixture* (*MyPrototype)();
这样在 DLL 中创建函数原型吗?
注意:一开始它没有为我编译(提供的代码不完整),所以我不得不进行一些更改,希望我保留了您想要的功能。
首先,关于 creating/using 个 DLL 的一些评论:
__declspec(dllexport)
仅在您要导入符号时才需要,如 create
。当您从 DLL 中创建对象时,不必导出 class 本身。
- 如果您按照自己的方式定义 class,编译器也会等待定义,它恰好在 DLL 中(并且该 DLL 没有提供带有定义的 .lib table).这意味着代码无法编译。
- 要解决这个问题,您可以:
- 你也导出 class,编译器生成一个 .lib 文件(至少在 VS 中)和 link 你的应用程序,这意味着所有
QLibrary
代码没有必要。
- 你把你的class转换成一个纯虚拟的class(这里只需要public成员),把它导出到DLL的内部class( 实现 class) 并使用
create
作为工厂(它创建了一个实现 class 的实例)。
由于您的目标似乎是使用 QLibrary
,也许是为了制作类似插件的功能,我向您展示第二种解决方案,如果您更喜欢另一种,请告诉我,我会将扩展答案以涵盖该内容。
基于纯虚拟的解决方案class
dll.h、public头文件,暴露class
的设计
#ifndef DIVFIXTURE_H
#define DIVFIXTURE_H
#include<QObject>
#include<QVariant>
class DivFixture : public QObject {
public:
virtual ~DivFixture() {}
virtual Q_INVOKABLE void setNumerator(QVariant num) = 0;
virtual Q_INVOKABLE void setDenominator(QVariant denom) = 0;
virtual Q_INVOKABLE QVariant quotient() = 0;
};
#endif
dll_impl.h,不打算在 DLL 之外使用,存储实际的
#ifndef DIVFIXTURE_IMPL_H
#define DIVFIXTURE_IMPL_H
#include "dll.h"
class DivFixture_Impl : public DivFixture {
public:
DivFixture_Impl();
virtual ~DivFixture_Impl() {}
virtual Q_INVOKABLE void setNumerator(QVariant num) override;
virtual Q_INVOKABLE void setDenominator(QVariant denom) override;
virtual Q_INVOKABLE QVariant quotient() override;
protected:
double numerator, denominator;
};
#endif
dll.cpp,实际执行
#include "dll_impl.h"
DivFixture_Impl::DivFixture_Impl() : numerator(0.0), denominator(1.0) {}
void DivFixture_Impl::setNumerator(QVariant num)
{
numerator = num.toDouble();
}
void DivFixture_Impl::setDenominator(QVariant denom)
{
denominator = denom.toDouble();
}
QVariant DivFixture_Impl::quotient()
{
QVariant ret;
ret = numerator / denominator;
return ret;
}
// non-class function to return pointer to class
extern "C" __declspec(dllexport) DivFixture* create()
{
return new DivFixture_Impl();
}
main.cpp
#include <QtCore>
#include "../dll/dll.h"
int main()
{
QLibrary library("dll.dll");
if (!library.load()) {
qDebug() << library.errorString();
return 0;
}
qDebug() << "library loaded";
typedef DivFixture * (*MyPrototype)();
auto myFunction = (MyPrototype)library.resolve("create");
qDebug() << myFunction;
DivFixture* r1 = nullptr;
if (myFunction)
r1 = myFunction();
if (r1 != nullptr) {
r1->setDenominator(2.0);
r1->setNumerator(10.0);
auto r = r1->quotient();
qDebug() << r.toDouble();
} else {
qDebug() << "r1 not created!";
}
return 0;
}
补充说明
关于崩溃,不管myFunction
是否为null,都会执行下面的第三行代码,所以崩溃实际上可能是因为r1
没有初始化。
if (myFunction)
r1=myFunction();
r1->quotient();
注意缩进和实际代码块之间的不一致。此处使用大括号:
if (myFunction) {
r1=myFunction();
r1->quotient();
}
或在使用前检查 r1
是否为空:
if (myFunction)
r1=myFunction();
if (r1 != nullptr)
r1->quotient();
此外,这可能只是一个拼写错误,但您检查了 if (myFunction)
,但在下一行中调用了 Function
而不是 myFunction
。头文件名也一样。发布代码时要小心这些事情,因为它们很难重现您的问题,因此您可能得不到答案或适当的答案。
最后,作为一个小提示,除非你想插入一个额外的空行,否则 qDebug
已经在末尾添加了一个换行符,所以没有必要使用 endl
.
我能够在 Qt main.cpp 中创建 class 的实例,但我的应用程序在尝试访问 DLL 的 class 成员函数时崩溃。
我该怎么做?
如果这是我的dll.h
#ifndef DIVFIXTURE_H
#define DIVFIXTURE_H
#include<QObject>
#include<QVariant>
class __declspec(dllexport) DivFixture : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE DivFixture();
Q_INVOKABLE void setNumerator(QVariant num);
Q_INVOKABLE void setDenominator(QVariant denom);
Q_INVOKABLE QVariant quotient();
private:
double numerator, denominator;
};
#endif
这是我的dll.cpp
#include "testfixture.h"
DivFixture::DivFixture(){}
void DivFixture::setNumerator(QVariant num)
{
numerator=num.toDouble();
}
void DivFixture::setDenominator(QVariant denom)
{
denominator=denom.toDouble();
}
QVariant DivFixture::quotient()
{
QVariant ret;
ret=numerator/denominator;
return ret;
}
//non-class function to return pointer to class
extern "C" __declspec(dllexport) DivFixture* create()
{
return new DivFixture();
}
这是我正在导入 DLL 库的 Qt 应用程序的 main.cpp
QLibrary library(("C:\somepath\testFixture.dll");
if (!library.load())
qDebug() << library.errorString() << endl;
if (library.load())
qDebug() << "library loaded" << endl;
DivFixture *r1=NULL;
typedef DivFixture* (*MyPrototype)();
auto myFunction = (MyPrototype)library.resolve("create");
qDebug()<<myFunction;
if (myFunction)
r1=Function(); // able to create instance of DivFixture
r1->quotient(); //I'm not able to access class member function
为什么我无法使用 class 实例访问 class 成员函数 quotient()
?程序在这一行崩溃 r1->quotient();
。我可以创建 class DivFixture
的原型来访问其成员函数,而不是像 typedef DivFixture* (*MyPrototype)();
这样在 DLL 中创建函数原型吗?
注意:一开始它没有为我编译(提供的代码不完整),所以我不得不进行一些更改,希望我保留了您想要的功能。
首先,关于 creating/using 个 DLL 的一些评论:
__declspec(dllexport)
仅在您要导入符号时才需要,如create
。当您从 DLL 中创建对象时,不必导出 class 本身。- 如果您按照自己的方式定义 class,编译器也会等待定义,它恰好在 DLL 中(并且该 DLL 没有提供带有定义的 .lib table).这意味着代码无法编译。
- 要解决这个问题,您可以:
- 你也导出 class,编译器生成一个 .lib 文件(至少在 VS 中)和 link 你的应用程序,这意味着所有
QLibrary
代码没有必要。 - 你把你的class转换成一个纯虚拟的class(这里只需要public成员),把它导出到DLL的内部class( 实现 class) 并使用
create
作为工厂(它创建了一个实现 class 的实例)。
- 你也导出 class,编译器生成一个 .lib 文件(至少在 VS 中)和 link 你的应用程序,这意味着所有
由于您的目标似乎是使用 QLibrary
,也许是为了制作类似插件的功能,我向您展示第二种解决方案,如果您更喜欢另一种,请告诉我,我会将扩展答案以涵盖该内容。
基于纯虚拟的解决方案class
dll.h、public头文件,暴露class
的设计#ifndef DIVFIXTURE_H
#define DIVFIXTURE_H
#include<QObject>
#include<QVariant>
class DivFixture : public QObject {
public:
virtual ~DivFixture() {}
virtual Q_INVOKABLE void setNumerator(QVariant num) = 0;
virtual Q_INVOKABLE void setDenominator(QVariant denom) = 0;
virtual Q_INVOKABLE QVariant quotient() = 0;
};
#endif
dll_impl.h,不打算在 DLL 之外使用,存储实际的
#ifndef DIVFIXTURE_IMPL_H
#define DIVFIXTURE_IMPL_H
#include "dll.h"
class DivFixture_Impl : public DivFixture {
public:
DivFixture_Impl();
virtual ~DivFixture_Impl() {}
virtual Q_INVOKABLE void setNumerator(QVariant num) override;
virtual Q_INVOKABLE void setDenominator(QVariant denom) override;
virtual Q_INVOKABLE QVariant quotient() override;
protected:
double numerator, denominator;
};
#endif
dll.cpp,实际执行
#include "dll_impl.h"
DivFixture_Impl::DivFixture_Impl() : numerator(0.0), denominator(1.0) {}
void DivFixture_Impl::setNumerator(QVariant num)
{
numerator = num.toDouble();
}
void DivFixture_Impl::setDenominator(QVariant denom)
{
denominator = denom.toDouble();
}
QVariant DivFixture_Impl::quotient()
{
QVariant ret;
ret = numerator / denominator;
return ret;
}
// non-class function to return pointer to class
extern "C" __declspec(dllexport) DivFixture* create()
{
return new DivFixture_Impl();
}
main.cpp
#include <QtCore>
#include "../dll/dll.h"
int main()
{
QLibrary library("dll.dll");
if (!library.load()) {
qDebug() << library.errorString();
return 0;
}
qDebug() << "library loaded";
typedef DivFixture * (*MyPrototype)();
auto myFunction = (MyPrototype)library.resolve("create");
qDebug() << myFunction;
DivFixture* r1 = nullptr;
if (myFunction)
r1 = myFunction();
if (r1 != nullptr) {
r1->setDenominator(2.0);
r1->setNumerator(10.0);
auto r = r1->quotient();
qDebug() << r.toDouble();
} else {
qDebug() << "r1 not created!";
}
return 0;
}
补充说明
关于崩溃,不管myFunction
是否为null,都会执行下面的第三行代码,所以崩溃实际上可能是因为r1
没有初始化。
if (myFunction)
r1=myFunction();
r1->quotient();
注意缩进和实际代码块之间的不一致。此处使用大括号:
if (myFunction) {
r1=myFunction();
r1->quotient();
}
或在使用前检查 r1
是否为空:
if (myFunction)
r1=myFunction();
if (r1 != nullptr)
r1->quotient();
此外,这可能只是一个拼写错误,但您检查了 if (myFunction)
,但在下一行中调用了 Function
而不是 myFunction
。头文件名也一样。发布代码时要小心这些事情,因为它们很难重现您的问题,因此您可能得不到答案或适当的答案。
最后,作为一个小提示,除非你想插入一个额外的空行,否则 qDebug
已经在末尾添加了一个换行符,所以没有必要使用 endl
.