我正在寻找开发一组C API,它们将围绕我们现有的C++ API来访问我们的核心逻辑(用面向对象的C++编写).这基本上是一个粘合API,允许我们的C++逻辑可以被其他语言使用.什么是一些很好的教程,书籍或最佳实践,介绍了围绕面向对象的C++包装C所涉及的概念?
Mic*_*son 65
这不是很难手工完成,而是取决于界面的大小.我完成它的情况是允许在纯C代码中使用我们的C++库,因此SWIG没有太大帮助.(好吧也许SWIG可以用来做这个,但我不是SWIG大师,它似乎不平凡)
我们最终做的就是:
所以像这样的类(C++头)
class MyClass
{
public:
explicit MyClass( std::string & s );
~MyClass();
int doSomething( int j );
}
Run Code Online (Sandbox Code Playgroud)
会映射到这样的C接口(C头):
struct HMyClass; // An opaque type that we'll use as a handle
typedef struct HMyClass HMyClass;
HMyClass * myStruct_create( const char * s );
void myStruct_destroy( HMyClass * v );
int myStruct_doSomething( HMyClass * v, int i );
Run Code Online (Sandbox Code Playgroud)
接口的实现看起来像这样(C++源代码)
#include "MyClass.h"
extern "C"
{
HMyClass * myStruct_create( const char * s )
{
return reinterpret_cast<HMyClass*>( new MyClass( s ) );
}
void myStruct_destroy( HMyClass * v )
{
delete reinterpret_cast<MyClass*>(v);
}
int myStruct_doSomething( HMyClass * v, int i )
{
return reinterpret_cast<MyClass*>(v)->doSomething(i);
}
}
Run Code Online (Sandbox Code Playgroud)
我们从原始类派生我们的不透明句柄以避免需要任何转换,并且(这似乎不适用于我当前的编译器).我们必须使句柄成为结构,因为C不支持类.
这样就给了我们基本的C接口.如果你想要一个更完整的例子,展示一种可以集成异常处理的方法,那么你可以在github上尝试我的代码:https://gist.github.com/mikeando/5394166
现在,有趣的部分是确保您正确地将所有必需的C++库链接到更大的库中.对于gcc(或clang),这意味着只使用g ++进行最后的链接阶段.
fig*_*ssa 14
我认为迈克尔安德森的答案是正确的,但我的方法会有所不同.你不得不担心一件事:例外.异常不是C ABI的一部分,因此您不能让Exceptions超越C++代码.所以你的标题看起来像这样:
#ifdef __cplusplus
extern "C"
{
#endif
void * myStruct_create( const char * s );
void myStruct_destroy( void * v );
int myStruct_doSomething( void * v, int i );
#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)
你的包装器的.cpp文件看起来像这样:
void * myStruct_create( const char * s ) {
MyStruct * ms = NULL;
try { /* The constructor for std::string may throw */
ms = new MyStruct(s);
} catch (...) {}
return static_cast<void*>( ms );
}
void myStruct_destroy( void * v ) {
MyStruct * ms = static_cast<MyStruct*>(v);
delete ms;
}
int myStruct_doSomething( void * v, int i ) {
MyStruct * ms = static_cast<MyStruct*>(v);
int ret_value = -1; /* Assuming that a negative value means error */
try {
ret_value = ms->doSomething(i);
} catch (...) {}
return ret_value;
}
Run Code Online (Sandbox Code Playgroud)
更好的是:如果你知道你需要的只是一个MyStruct的单个实例,那么就不要冒着处理传递给你的API的void指针的风险.做这样的事情:
static MyStruct * _ms = NULL;
int myStruct_create( const char * s ) {
int ret_value = -1; /* error */
try { /* The constructor for std::string may throw */
_ms = new MyStruct(s);
ret_value = 0; /* success */
} catch (...) {}
return ret_value;
}
void myStruct_destroy() {
if (_ms != NULL) {
delete _ms;
}
}
int myStruct_doSomething( int i ) {
int ret_value = -1; /* Assuming that a negative value means error */
if (_ms != NULL) {
try {
ret_value = _ms->doSomething(i);
} catch (...) {}
}
return ret_value;
}
Run Code Online (Sandbox Code Playgroud)
这个API更安全.
但是,正如迈克尔所说,链接可能会变得非常棘手.
希望这可以帮助
hha*_*fez 10
将C++代码暴露给C并不难,只需使用Facade设计模式即可
我假设您的C++代码内置于库中,您只需将C++库中的一个C模块作为库的Facade和纯C头文件.C模块将调用相关的C++函数
完成后,您的C应用程序和库将完全访问您公开的C api.
例如,这是一个示例Facade模块
#include <libInterface.h>
#include <objectedOrientedCppStuff.h>
int doObjectOrientedStuff(int *arg1, int arg2, char *arg3) {
Object obj = ObjectFactory->makeCppObj(arg3); // doing object oriented stuff here
obj->doStuff(arg2);
return obj->doMoreStuff(arg1);
}
Run Code Online (Sandbox Code Playgroud)
然后,您将此C函数公开为您的API,您可以将其作为C lib自由使用而不用担心
// file name "libIntrface.h"
extern int doObjectOrientedStuff(int *, int, char*);
Run Code Online (Sandbox Code Playgroud)
显然这是一个人为的例子,但这是将C++库暴露给C的最简单方法
我认为你可能能够获得关于方向的一些想法和/或可能直接利用SWIG.我认为,通过一些示例,至少可以让您了解在将一个API包装到另一个API时需要考虑的事项.这项运动可能是有益的.
SWIG是一个软件开发工具,它将用C和C++编写的程序与各种高级编程语言连接起来.SWIG与不同类型的语言一起使用,包括常见的脚本语言,如Perl,PHP,Python,Tcl和Ruby.支持的语言列表还包括非脚本语言,如C#,Common Lisp(CLISP,Allegro CL,CFFI,UFFI),Java,Lua,Modula-3,OCAML,Octave和R.还有几种解释和编译的Scheme实现(支持Guile,MzScheme,Chicken).SWIG最常用于创建高级解释或编译的编程环境,用户界面,以及作为测试和原型化C/C++软件的工具.SWIG还可以以XML和Lisp s表达式的形式导出其解析树.SWIG可以自由使用,分发,