У меня есть два модуля, каждый со своим классом и со своим объектом. Каждый модуль скомпилирован в DLL. Я хочу сделать вызов метода «кросс-DLL», имея указатель на объект другого класса, но компоновщик не позволяет это сделать (MSVC ++ 2008).
Более конкретно:
Я могу скомпилировать весь код. Проблема возникает, когда запускается компоновщик. Я получаю следующее:
moduleCalling.obj: ошибка LNK2001: неразрешенный внешний символ «public: void __thiscall classCalled :: methodCalled …»
Я не использую никакие вещи declspec, поэтому ничего не экспортируется из файла namedLib.dll.
Метод, который я вызываю (methodCalled), присутствует в реализации, его прототип правильно объявлен в заголовке. ClassCalled является «базовым» классом, не наследуемым ни от чего.
Более того, весь проект компилируется и работает правильно, когда я объявляю methodCalled виртуальным …
У меня проблемы с пониманием, почему я не могу вызвать метод объекта «обычным» способом из другой DLL? Почему декларация «виртуальная» помогает? Кто-нибудь знает? У меня есть некоторые предположения, но экспертный ответ очень поможет понять этот материал.
П.С .: Я использую MSVC ++ 2008.
Спасибо!
Обновление: добавление фрагмента кода, который отражает, как выглядит код.
// part of calledLib.dll
// moduleCalled.h
class classCalled {
public:
int methodCalled() { return 1 };
};
// ---------------------------------------------------------------
// part of callingLib.dll
// moduleCalling.h
#include "moduleCalled.h"
class classCalling {
public:
classCalled* ref;
void justSomeMethod();
};
// ---------------------
// moduleCalling.cpp
#include "moduleCalling.h"
void classCalling::justSomeMethod() {
ref = new classCalled();
int a = ref->methodCalled(); // <--- this is not allowed by linker,
// unless methodCalled is made virtual.
}
Линкер связывает фрагменты кода из различных модулей. Если у вас есть вызов из одного модуля в другой, компоновщик должен знать, в каком другом модуле реализована вызываемая вами функция, и заменить вызов реальным адресом. Это очень грубая картина, но этого достаточно, чтобы понять, что происходит.
В вашем случае компоновщик должен знать, что ваша функция находится в namedLib.dll. Поэтому вы должны связать с чем-то, что называется Lib.dll. Это что-то называется библиотека импорта. Его имя должно называться Lib.lib. Чтобы сгенерировать его, вы должны либо написать файл .def, но это трудно для методов класса, так как имена методов класса, используемые компоновщиком, выглядят очень иначе, чем они выглядят в вашем коде C ++. Или вы можете использовать declspecs. Он сгенерирует правильный файл namedLib.lib, который вы должны будете связать с вашим callLib.dll.
Других решений пока нет …