2014-10-07 17 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