在Qt

时间:2017-05-04 12:11:32

标签: c++ qt dll dllexport qlibrary

我能够在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();
}

这是我的Qt应用程序的main.cpp,我导入了DLL库

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中创建函数的原型,我可以创建类DivFixture的原型来访问其成员函数吗?

1 个答案:

答案 0 :(得分:0)

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

首先,关于创建/使用DLL的一些注释:

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

    的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。< / p>