QLibrary — импортировать класс

У меня есть библиотека QT, и я хочу импортировать ее в другой проект.

Теперь, когда я хочу, чтобы, даже когда я изменял библиотеку, другой проект не нужно было снова компилировать, я начал использовать 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)" (__imp_?getValues@TestDLL_lib@@QAEHXZ)

Как я могу решить это? Можно ли вызывать методы из импортированных классов?

Спасибо..

5

Решение

Вы не можете вызывать методы для классов, импортированных во время выполнения. Это потому, что компилятор связывает эти вызовы во время компиляции, а не во время выполнения (что он не могу сделать). Выход из ситуации предоставлен нашим добрым старым другом, vtable:

Ты можешь позвонить virtual методы в классах, реализующих интерфейс (интерфейс не «импортируется» во время выполнения). Это означает определить класс, определяющий интерфейс, используя virtual (возможно, чисто виртуальные) методы. TestDLL_lib затем наследовал бы этот интерфейс, реализуя методы. Вы бы ссылались на TestDLL_lib через этот интерфейс и вызывать методы через этот интерфейс, эффективно вызывая их через виртуальную таблицу интерфейса, которая «заменяется» TestDLL_libс vtable.

Не забудьте сделать свой д’тор virtual и добавить virtual дтор до интерфейса. Если вы этого не сделаете, вы не можете безопасно 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();
}
6

Другие решения


По вопросам рекламы [email protected]