gpt4 book ai didi

从具有基类和接口(interface)的 c++ 类使用 SWIG 生成 Java 类

转载 作者:行者123 更新时间:2023-11-30 04:21:28 28 4
gpt4 key购买 nike

我正在将一个 C++ 应用程序移植到 Java。我使用 SWIG 生成了一些 Java 类和 JNI 包装器。

在 c++ 中,我有一个名为 Lion 的类,它扩展了 Animal 并实现了 Killable。我收到一条警告,说 Java 中不存在多重继承。到目前为止没问题,Lion 只会在我的 Java 类中扩展 Animal。

使用 SWIG 生成的类:

public class Killable {
private long swigCPtr;
protected boolean swigCMemOwn;

public Killable(long cPtr, boolean cMemoryOwn) {
swigCMemOwn = cMemoryOwn;
swigCPtr = cPtr;
}

protected static long getCPtr(Killable obj) {
return (obj == null) ? 0 : obj.swigCPtr;
}

protected void finalize() {
delete();
}

public synchronized void delete() {
if (swigCPtr != 0) {
if (swigCMemOwn) {
swigCMemOwn = false;
cppinterfaceJNI.delete_Killable(swigCPtr);
}
swigCPtr = 0;
}
}

public long getKillableId() {
return cppinterfaceJNI.Killable_getId(swigCPtr, this);
}

public void kill() {
cppinterfaceJNI.Killable_kill(swigCPtr, this);
}
}


public class Lion extends Animal {
private long swigCPtr;

public Lion(long cPtr, boolean cMemoryOwn) {
super(cppinterfaceJNI.Lion_SWIGUpcast(cPtr), cMemoryOwn);
swigCPtr = cPtr;
}

public static long getCPtr(Lion obj) {
return (obj == null) ? 0 : obj.swigCPtr;
}

...
}

现在假设我想要一个 Killable 数组。由于使用 SWIG 生成的 Java 类存储了指向原始 C++ 类的指针,因此我应该能够执行类似以下操作:

LinkedList<Killable> list = new LinkedList<Killable>();
Killable k = new Killable(Lion.getCPtr(myLionObject), false);
list.add(k);
System.out.println(k.getKillableId()) // Return a long, no crash here but I got a huge number (wrong number)
k.kill(); // Crash

当我这样做时没有错误,但是当我尝试访问我的对象 k 的方法时,库崩溃了。我认为崩溃的发生是因为没有找到合适的实现,但我不明白为什么,因为我给了一个指向新对象的有效指针。知道为什么会发生崩溃或我可以在这里使用的解决方法吗?

谢谢你的帮助

最佳答案

如您所见SWIG+Java doesn't result in pure virtual classes becoming interfaces automatically 的组合.

问题是,像您展示的那样直接使用 getCPtr() 操作对象类似于编写如下内容:

Lion *l = new lion;
intptr_t ptr = (intptr_t)l;
Killable *k = (Killable*)ptr;

在 C++ 中——像这样使用 C 风格的转换是一种不好的形式,因为它们掩盖了未定义的行为。它极不可能按预期工作,即使它按预期工作也会比崩溃更糟糕,因为你的代码库中有未诊断的未定义行为。幸运的是,使用 SWIG 有一个简单的解决方法,您仍然可以在其中进行这样的转换(通常只是自动转换)。

假设我们有如下头文件:

#include <iostream>

class Killable {
public:
virtual ~Killable() {}
virtual void die() = 0;
};

class Animal {
public:
virtual ~Animal() {}
virtual void moo() { std::cout << "The dog says: meow\n"; }
};

class Lion : public Animal, public Killable {
virtual void die() { std::cout << "Deaded\n"; }
};

我们可以使用以下 SWIG 接口(interface)成功包装它:

%module test

%{
#include "test.h"
%}

%include "test.h"

%extend Animal {
Killable *toKillable() {
return dynamic_cast<Killable*>($self);
}
}

在这里,%extend 添加了另一个成员函数来处理不会自动暴露的类型转换。如果转换正常,则返回有效的 Killable。如果不是,则将返回 null

我们可以在 Java 中使用它:

import java.util.LinkedList;

public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
LinkedList<Killable> list = new LinkedList<Killable>();
Lion l = new Lion();
l.moo();
Killable k = l.toKillable();
list.add(k);
k.die();
}
}

关于从具有基类和接口(interface)的 c++ 类使用 SWIG 生成 Java 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14523978/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com