2014-10-07 66 views
4

我有一个QT库,我想在另一个项目中导入它。QLibrary - 进口一个类

现在,因为我想这样,即使当我修改库时,其他项目不需要再次编译,我开始使用QLibrary。

但是...我无法导入类。或者更好,我可以导入这个类,但是我不能访问它的方法。

这是我做的例子。

这是类声明:

class TESTDLL_LIBSHARED_EXPORT TestDLL_lib 
{ 

public: 
    TestDLL_lib(); 

    int a; 
    int b; 
    int c; 

    int getValues(); 
}; 

,这实现:

#include "testdll_lib.h" 

TestDLL_lib::TestDLL_lib() 
{ 
    a = 10; 
    b = 20; 
    c = 30; 
} 

int TestDLL_lib::getValues() 
{ 
    return a+b+c; 
} 

extern "C" TESTDLL_LIBSHARED_EXPORT TestDLL_lib* create_TestDLL_lib() 
{ 
    return new TestDLL_lib(); 
} 

,而这是主要的文件,在其他项目:

#include <testdll_lib.h> 
#include <QDebug> 
#include <QLibrary> 

int main(int argc, char *argv[]) 
{ 
    QLibrary library("TestDLL_lib"); 
    if (library.load()) 
    { 
     typedef TestDLL_lib* (*create_TestDLL_lib_fun)(); 
     create_TestDLL_lib_fun create_TestDLL_lib = (create_TestDLL_lib_fun)library.resolve("create_TestDLL_lib"); 

     if (create_TestDLL_lib) 
     { 
      TestDLL_lib *myClassInstance = create_TestDLL_lib(); 

      if (myClassInstance) 
      { 
       //qDebug() << QString::number(myClassInstance->getValues()); 
       qDebug() << QString::number(myClassInstance->a) + " " + QString::number(myClassInstance->b) + " " + QString::number(myClassInstance->c); 
      } 
     } 

     library.unload(); 
    } 
} 

现在,我可以访问所有的数据值(a,b,c)对象myClassInstance(如果我在DLL中改变他们,他们也得到程序中的改变不会重建),但我不能叫myClassInstance->getValues(),因为我得到

main.obj:-1: error: LNK2001: unresolved external symbol "__declspec(dllimport) public: int __thiscall TestDLL_lib::getValues(void)" ([email protected][email protected]@QAEHXZ) 

我怎样才能解决这个问题的?是否可以从导入的类中调用方法?

谢谢..

回答

5

您不能调用在运行时导入的类的方法。这是因为编译器在编译时链接这些调用,而不是在运行时(它不能在中执行)。一个出路是由我们的友好好友提供的,这个vtable:

您可以调用virtual实现接口的类的方法(该接口在运行时不是“导入”的)。这意味着使用virtual(可能是纯虚拟)方法来定义定义接口的类。然后TestDLL_lib将继承该接口,实现这些方法。您将通过该接口参考TestDLL_lib实例,并通过该接口调用方法,通过接口的vtable有效地调用它们,该接口由TestDLL_lib s vtable“替代”。

不要忘了让你的手指virtual并添加一个virtual dtor到接口。如果你不这样做,你不能安全delete实例通过接口指针。

我也可以解释为什么你可以访问成员,但不能调用“导入”类的函数。成员可以通过内存位置访问,并且内存位置完全由编译器定义。因此,编译器会生成代码以访问成员,而不会引用任何类的符号(方法等)。这反过来导致没有链接依赖性。但是请注意,如果更改了类,则需要使用DLL重新编译DLL和应用程序。添加或删除成员,因为这会更改内存布局。

class TestInterface 
{ 
public: 
    virtual ~TestInterface() 
    { 
    } 

    virtual int getValues() = 0; 
} 

class TESTDLL_LIBSHARED_EXPORT TestDLL_lib : public TestInterface 
{ 

public: 
    TestDLL_lib(); 
    virtual ~TestDLL_lib(); 

    int a; 
    int b; 
    int c; 

    int getValues() override; // MSVC may not support "override" 
}; 

// return pointer to interface! 
// TestDLL_lib can and should be completely hidden from the application 
extern "C" TESTDLL_LIBSHARED_EXPORT TestInterface *create_TestDLL_lib() 
{ 
    return new TestDLL_lib(); 
} 
+0

谢谢!有用! :) – frarugi87 2014-10-07 12:44:35

+0

另请参见:[使用插件扩展Qt应用程序](http://qt-project.org/doc/qt-5/plugins-howto.html#the-lower-level-api-extending-t-t-t-applications) – dom0 2014-10-07 15:46:57