我有一组相关的C ++类必须被包裹并以这样的方式,它可以通过C / FFI文库中容易地消耗从DLL导出的。 我在寻找做一些这方面的“最佳实践”。 例如,如何创建和免费的对象,如何处理基类,可选择的解决方案,等等。
一些基本准则,我至今是方法转化为简单的功能转换与代表this指针,包括任何析构一个额外的void *的说法。 构造函数可以保留原来的参数列表,但必须返回表示对象的指针。 所有的内存应该通过相同的一组进程级的分配和释放例程,无论是通过宏或以其他方式进行处理,而应该是支持热插拔的意义。
我有一组相关的C ++类必须被包裹并以这样的方式,它可以通过C / FFI文库中容易地消耗从DLL导出的。 我在寻找做一些这方面的“最佳实践”。 例如,如何创建和免费的对象,如何处理基类,可选择的解决方案,等等。
一些基本准则,我至今是方法转化为简单的功能转换与代表this指针,包括任何析构一个额外的void *的说法。 构造函数可以保留原来的参数列表,但必须返回表示对象的指针。 所有的内存应该通过相同的一组进程级的分配和释放例程,无论是通过宏或以其他方式进行处理,而应该是支持热插拔的意义。
的foreach公共方法,你需要一个C函数。
您还需要一个不透明的指针代表在C代码的类。
这是简单,只需使用一个void *虽然你可以建立一个包含一个void *和其它信息的结构(例如,如果你想支持数组?)。
Fred.h
--------------------------------
#ifdef __cplusplus
class Fred
{
public:
Fred(int x,int y);
int doStuff(int p);
};
#endif
//
// C Interface.
typedef void* CFred;
//
// Need an explicit constructor and destructor.
extern "C" CFred newCFred(int x,int y);
extern "C" void delCFred(CFred);
//
// Each public method. Takes an opaque reference to the object
// that was returned from the above constructor plus the methods parameters.
extern "C" int doStuffCFred(CFred,int p);
的实现很简单。
不透明指针转换为弗雷德,然后调用方法。
CFred.cpp
--------------------------------
// Functions implemented in a cpp file.
// But note that they were declared above as extern "C" this gives them
// C linkage and thus are available from a C lib.
CFred newCFred(int x,int y)
{
return reinterpret_cast<void*>(new Fred(x,y));
}
void delCFred(CFred fred)
{
delete reinterpret_cast<Fred*>(fred);
}
int doStuffCFred(CFred fred,int p)
{
return reinterpret_cast<Fred*>(fred)->doStuff(p);
}
虽然洛基阿斯塔的回答非常好,他的样本代码把C ++类里面的封装代码。 我希望有一个单独的文件的封装代码。 此外,我认为这是更好的风格前缀包装的C函数的类名。
下面的博客文章介绍如何做到这一点: http://blog.eikke.com/index.php/ikke/2005/11/03/using_c_classes_in_c.html
我复制的重要组成部分,因为博客是被遗弃的,可能最终消失(信贷IKKE的博客):
首先,我们需要一个C ++类,使用一个头文件(Test.hh)
class Test {
public:
void testfunc();
Test(int i);
private:
int testint;
};
和一个实现文件(Test.cc)
#include <iostream>
#include "Test.hh"
using namespace std;
Test::Test(int i) {
this->testint = i;
}
void Test::testfunc() {
cout << "test " << this->testint << endl;
}
这仅仅是基本的C ++代码。
然后,我们需要一些胶水代码。 此代码是在两者之间的C和C ++的东西。 再次,我们得到了一个头文件(TestWrapper.h,只是.H因为它不包含任何C ++代码)
typedef void CTest;
#ifdef __cplusplus
extern "C" {
#endif
CTest * test_new(int i);
void test_testfunc(const CTest *t);
void test_delete(CTest *t);
#ifdef __cplusplus
}
#endif
和功能实现(TestWrapper.cc,.CC因为它包含C ++代码):
#include "TestWrapper.h"
#include "Test.hh"
extern "C" {
CTest * test_new(int i) {
Test *t = new Test(i);
return (CTest *)t;
}
void test_testfunc(const CTest *test) {
Test *t = (Test *)test;
t->testfunc();
}
void test_delete(CTest *test) {
Test *t = (Test *)test;
delete t;
}
}
首先,你可能不需要所有的方法转换为C函数。 如果你能简化API并隐藏了一些C ++接口,它是更好,因为你尽量减少改变C API,当你改变落后C ++逻辑的机会。
因此,认为更高的抽象层次上通过API提供。 用你的描述void *的解决方案。 在我看来最合适的(或无效的typedef *为HANDLE :))。
从我的经验几点看法:
例如:
C_ERROR BuildWidget(HUI ui, HWIDGET* pWidget);
例如,你的函数应该是这样的:
C_ERROR BuildWidget(HUI ui, HWIDGET* pWidget){
Ui* ui = (Ui*)ui;
if(ui.Signature != 1234)
return BAD_HUI;
}
例如:
C_ERROR CreateUi(HUI* ui);
C_ERROR CloseUi(HUI hui); // usually error codes don't matter here, so may use void
例如:
C_ERROR CreateBitmap(HUI* ui, SIZE size, char** pBmpBuffer, int* pSize);
Image
,并提供通过访问它HIMG
手柄,提供的功能将其转换为从如Windows HBITMAP) 。 这将简化与现有的API集成。 如
C_ERROR BitmapToHBITMAP(HUI* ui, char* bmpBuffer, int size, HBITMAP* phBmp);
使用载体(和串:: c_str)与非C ++的API交换数据。 (准则#78从C ++编码标准 ,H.萨特/ A. Alexandrescu的)。
PS这不是真的,“构造函数可以保留其原有的参数列表”。 这仅仅是参数类型它们是C兼容真。
PS2当然,听白内停 ,并保持你的界面小而简单越好。
这可能是兴趣: “混合C和C ++”在C ++ FAQ精简版。 具体地说[32.8]如何可以从C函数通过C ++类的一个目的是/?