【发布时间】:2011-08-23 21:13:36
【问题描述】:
我有一个非常庞大且成熟的 C++ 代码库,我正在尝试使用 SWIG 为其生成 C# 接口。我无法更改实际的 C++ 代码本身,但我们可以使用 SWIG 提供的任何东西来扩展/更新它。我面临一个问题,即如下编写的 C++ 函数在 C# 中引起问题。
A* SomeClass::next(A*)
调用者可能会执行以下操作:
A* acurr = 0;
while( (acurr = sc->next(acurr)) != 0 ){
if( acurr isoftype B ){
B* b = (B*)a;
...do some stuff with b..
}
elseif( acurr isoftype C )
...
}
本质上,遍历一个元素容器,根据它们的真实类型,做不同的事情。遗憾的是,SWIG 为“next”函数生成了 C# 层:
return new A();
因此,C# 中的调用代码无法确定返回的对象是否实际上是派生类,它实际上似乎始终是基类(这确实有意义)。我遇到了几种解决方案:
- 使用 %extend SWIG 关键字在对象上添加方法并最终调用 dynamic_cast。在我看来,这种方法的缺点是需要您了解继承层次结构。就我而言,它相当大,我认为这是一个维护问题。
- 使用 %factory 关键字来提供方法和派生类型,并让 SWIG 自动生成 dynamic_cast 代码。这似乎是一个比第一个更好的解决方案,但是在更深入的研究中,它仍然需要您寻找它可能返回的所有方法和所有可能的派生类型。再次,一个巨大的维护问题。我希望我有一个文档链接,但我找不到。我通过查看 SWIG 附带的示例代码发现了这个功能。
- 创建 C# 方法以创建派生对象的实例并将 cPtr 传输到新实例。虽然我认为这很笨拙,但它确实有效。请参阅下面的示例。
这些真的是选项吗?如果我不愿意挖掘所有现有的函数和类派生,那么我只剩下#3了吗?任何帮助将不胜感激。
【问题讨论】:
-
如果我可以问的话,您采用了哪种解决方案?我在另一种目标语言中面临一个非常相似的问题……