Обычно каждая единица перевода генерирует объектный файл, содержащий определения символов, определенных в этой единицы перевода. Чтобы использовать эти символы, вам необходимо связать эти объектные файлы.
В разделе gcc вы должны указать все объектные файлы, которые должны быть связаны вместе в командной строке, или скомпилировать файлы реализации вместе.
g++ -o test objectFile1.o objectFile2.o -lLibraryName
Здесь libraryName
- это просто имя библиотеки, без добавления к платформе. Так, например, в файлах библиотеки Linux обычно называют libfoo.so
, но вы должны писать только -lfoo
. В Windows этот же файл можно назвать foo.lib
, но вы будете использовать тот же аргумент. Возможно, вам придется добавить каталог, в котором эти файлы можно найти, используя -L‹directory›
. Обязательно не записывайте пробел после -l
или -L
.
Для XCode: добавьте пути поиска заголовка пользователя -> добавьте путь поиска библиотеки -> перетащите фактическую ссылку библиотеки в
В MSVS файлы, добавленные в проект, автоматически связывают их объектные файлы, и будет создан файл lib
(в общем использовании). Чтобы использовать символы в отдельном проекте, вам нужно будет добавить файлы lib
в параметры проекта. Это делается в разделе Linker свойств проекта в Input -> Additional Dependencies
. (путь к файлу lib
должен быть добавлен в Linker -> General -> Additional Library Directories
). При использовании сторонней библиотеки, которая предоставляется с файлом lib
, отказ в этом обычно приводит к ошибке.
Также может случиться так, что вы забудете добавить файл в компиляцию, и в этом случае объектный файл не будет сгенерирован. В gcc вы должны добавить файлы в командную строку. В MSVS добавление файла в проект заставит его скомпилировать его автоматически (хотя файлы могут, вручную, быть отдельно исключены из сборки).
В программировании Windows контрольный знак, который вы не связывали необходимая библиотека состоит в том, что имя неразрешенного символа начинается с __imp_
. Посмотрите имя функции в документации, и она должна сказать, какую библиотеку вам нужно использовать. Например, MSDN помещает информацию в поле внизу каждой функции в разделе «Библиотека».
Давайте рассмотрим, что у нас есть класс C ++:
class iVehicle
{
public:
virtual void Run() {}; // not-pure virtual here for simplicity of a wrapper, but could be pure (see the end of the post)
virtual int GetSize() const; // we want to reuse it in Java
};
Мы хотим создать класс Bot
в Java, который расширяет класс iVehicle
в том смысле, что вызовы super
вызывают C ++ кода из iVehicle::GetSize()
, а с точки зрения C ++ мы можем использовать экземпляры Bot
в качестве переменных iVehicle*
. Это сложно, так как C ++ не имеет хороших встроенных функций для отражения.
Вот одно из возможных решений.
Чтобы использовать класс C ++ в Java, нам нужно сгенерировать оболочку Java, то есть:
class iVehicle
{
public void Run() { Native_Run(); }
public int GetSize() { return Native_GetSize(); }
private native void Native_Run();
private native int Native_GetSize();
// typecasted to pointer in C++
private int NativeObjectHolder;
// create C++ object
native static private int CreateNativeObject();
}
Использование в Java просто:
class Bot extends iVehicle
{
public int GetSize()
{
if ( condition ) return 0;
// call C++ code
return super.GetSize();
}
}
Однако для этого кода есть часть C ++:
static jfieldID gNativeObjectHolderFieldID;
JNIEXPORT void JNICALL Java_com_test_iVehicle_Run( JNIEnv* env, jobject thiz )
{
int Value = env->GetIntField(thiz, gNativeObjectHolderFieldID);
iVehicle* Obj = (iVehicle*)Obj;
// todo: add checks here, for NULL and for dynamic casting
Obj->Run();
}
Аналогичный код для GetSize()
.
Затем, создав экземпляр Java Bot
, вы должны вызвать CreateNativeObject()
и назначить возвращаемое значение в поле NativeObjectHolder
.
JNIEXPORT int JNICALL Java_com_test_iVehicle_CreateNativeObject( JNIEnv* env, jobject thiz )
{
iVehicle* Obj = new iVehicle;
return (int)Obj;
}
Итак, это схема. Чтобы выполнить эту работу, вам нужно будет добавить код уничтожения и проанализировать классы C ++ для генерации всего этого кода.
Добавлено:
В случае, когда iVehicle
фактически является абстрактным, вы вам нужно создать не абстрактную оболочку, которую вы можете создать:
class iVehicle
{
virtual void Run() = 0;
}
class iVehicle_Wrapper: public iVehicle
{
virtual void Run() { ERROR("Abstract method called"); };
}
И создать экземпляр iVehicle_Wrapper
в CreateNativeObject()
. Vuala! Вы наследовали абстрактный класс C ++ в Java.