繁体   English   中英

在 Qt 中访问 DLL 的 C++ 类成员函数

[英]Accessing C++ class member functions of a DLL in Qt

我能够在 Qt main.cpp 中创建类的实例,但我的应用程序在尝试访问 DLL 的类成员函数时崩溃。

我该怎么做?

如果这是我的 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

为什么我无法使用类实例访问类成员函数quotient() 程序在这一行崩溃r1->quotient(); . 而不是像typedef DivFixture* (*MyPrototype)();那样在 DLL 中创建函数的原型typedef DivFixture* (*MyPrototype)(); ,我可以创建我的类DivFixture的原型来访问它的成员函数吗?

注意:它起初并没有为我编译(提供的代码不完整),所以我不得不进行一些更改,希望我保留了您想要的功能。

首先,关于创建/使用 DLL 的一些评论:

  1. __declspec(dllexport)仅在您想导入符号时才需要,就像create 当您从 DLL 中创建对象时,不必导出类本身。
  2. 如果你按照你的方式定义你的类,编译器也会等待定义,它恰好在 DLL 中(并且该 DLL 没有提供带有定义表的 .lib)。 这意味着代码将无法编译。
  3. 要解决此问题,您可以:
    • 您也导出该类,编译器会生成一个 .lib 文件(至少在 VS 中)并将您的应用程序与其链接,这意味着不需要所有QLibrary代码。
    • 您将类转换为纯虚拟类(此处仅需要公共成员),将其派生为 DLL 的内部类(实现类)并使用create作为工厂(它创建实现类的实例)。

由于您似乎打算使用QLibrary ,也许是为了制作类似插件的功能,我向您展示了第二种解决方案,如果您更喜欢另一种解决方案,请告诉我,我将扩展答案以涵盖该问题。

基于纯虚类的解决方案

dll.h,公共头文件,暴露类的设计

#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();
}

主程序

#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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM