我正在编写一个旨在在不同平台上运行的应用程序。我的基础库是用 C++ 编写的,我想使用 SWIG 生成特定于平台的代码(Java/Android、C#/Windows、Objective C/iOS)。
在这里,我正在使用我想从 Java -> C++ 和 C++ -> Java 传递的消息对象。这个想法是,有一个基本类型“CoreMessage”和派生消息“StatusMessage”、“DebugMessage”......
对我来说,通过执行以下操作来保持界面通用性似乎很自然:
C++:
class CoreMessage {
}
class StatusMessage : public CoreMessage {
public:
string getStatusMessage();
}
class DebugMessage : public CoreMessage {
public:
... some stuff
}
C++ 中的(双向)接口代码应如下所示:
CoreMessage waitForNextMessage(); // Java calls this and blocks until new message is available in a message queue
void processMessage(CoreMessage m); // Java calls this and puts a new message in an eventhandling mechanism
我的 Swig 文件非常基础,它只包含类定义和接口——仅此而已。
现在 Swig 为 Java 生成了所有的类和接口,包括 Java 中消息的继承:
public class CoreMessage {
...
}
public class StatusMessage extends CoreMessage {
...
}
public class DebugMessage extends CoreMessage {
...
}
主要的 Java 模块现在看起来像这样:
public native void processMessage(CoreMessage);
public native CoreMessage waitForNextMessage();
当我尝试像这样从 Java 调用此代码时:
StatusMessage m = new StatusMessage();
processMessage(m);
C++ 中的这段代码将被执行并导致错误:
void processMessage(CoreMessage in) {
StatusMessage* statusPtr = dynamic_case<StatusMessage*>(&in); // works
StatusMessage status = *(statusPtr); // This will cause a runtime error
}
另一个方向的同样问题:C++ 代码
TsCoreMessage waitForMessage() {
StatusMessage m = StatusMessage();
return m;
}
使用此 Java 代码,通过 JNI 和 SWIG 生成的包装器调用 C++:
CoreMessage msg = waitForMessage();
// msg instanceof StatusMessage returns false
StatusMessage s = (StatusMessage) msg; // Causes java.lang.ClassCaseException
所以对我来说,当将对象从一种语言传递到另一种语言时,JNI 似乎丢失了类型信息......
我确实阅读了一些线程和文章,但我没有找到解决方案 - 我需要一个双向解决方案。
我不确定“导演”不是我要找的吗?据我了解导演,它们是为类制作的,在java中手动扩展并允许向上转换到相应的C++ BaseClass ...但我不确定我对导演的理解;-)