如何设计一个C和C+中具有并行接口的库+; 我目前的项目是一个中型图书馆,它同时也有C和C++接口。它围绕着一个数据类型,我希望从C和C++函数中访问它,因为我想鼓励第三方通过编写任何一种语言的函数来扩展库。
我了解C/C++混合的基础知识(例如比较),并提出了以下解决方案: <>我的基本设计集中在C中创建一个结构,所有的数据都被暴露出来(这是我的C程序员所期望的),并且从中派生出一个隐藏成员访问的类,希望能够更安全地访问C++程序员的结构。问题是从派生出来的:我想在C++中使用命名空间,隐藏C接口。当然,C结构本身不能隐藏(不使用PIMPL习惯用法),但这对我来说很好 下面的示例代码编译并运行时,C和C++的“客户端”程序没有明显错误。然而,我想知道这个解决方案是有效的还是有更好的解决方案 示例代码:如何设计一个C和C+中具有并行接口的库+; 我目前的项目是一个中型图书馆,它同时也有C和C++接口。它围绕着一个数据类型,我希望从C和C++函数中访问它,因为我想鼓励第三方通过编写任何一种语言的函数来扩展库。,c++,c,namespaces,derived-class,interface-design,C++,C,Namespaces,Derived Class,Interface Design,我了解C/C++混合的基础知识(例如比较),并提出了以下解决方案: 我的基本设计集中在C中创建一个结构,所有的数据都被暴露出来(这是我的C程序员所期望的),并且从中派生出一个隐藏成员访问的类,希望能够更安全地访问C++程序员的结构。问题是从派生出来的:我想在C++中使用命名空间,隐藏C接口。当然,C结构本身不能隐藏(不使用PIMPL习惯用法),但这对我来说很好 下面的示例代码编译并运行时,C和C++的“客户端”程序没有明显错误。然而,我想知道这个解决方案是有效的还是有更好的解决方案 示例代码:
#ifdef __cplusplus__
extern "C" {
#endif
struct base
{
char * data;
}
#ifdef __cplusplus__
} // extern "C"
namespace {
extern "C" {
#endif
/* cleanly initialize struct */
struct base * new_base (struct base *);
/* cleanly destroy struct */
void del_base (struct base *);
#ifdef __cplusplus__
} } // namespace, extern "C"
#include<new>
namespace safe {
class base_plus : private base
{
public:
base_plus ()
{
if (! new_base(this))
throw std::bad_alloc ();
}
~base_plus ()
{
del_base (this);
}
};
} // namespace safe
#endif
\ifdef\uuucplusplus__
外部“C”{
#恩迪夫
结构基
{
字符*数据;
}
#ifdef_uucplusplus__
}//外部“C”
名称空间{
外部“C”{
#恩迪夫
/*干净地初始化结构*/
结构基础*新基础(结构基础*);
/*彻底摧毁结构*/
void del_基底(结构基底*);
#ifdef_uucplusplus__
}}//名称空间,外部“C”
#包括
命名空间安全{
类库_plus:专用库
{
公众:
基数加()
{
如果(!新_基地(本))
抛出std::bad_alloc();
}
~base_plus()
{
德鲁基地(本);
}
};
}//命名空间安全
#恩迪夫
实际上,另一种方法是在C++中编写完整的代码,只使用数据隐藏技术编写一个C SLIM接口。
namespace Foo {
class Bar {
public:
int property1() const;
std::string const& property2() const;
};
}
在C兼容的头文件中:
#ifdef __cplusplus__
extern "C" {
#endif
typedef void* Bar;
Bar foo_bar_new(int i, char const* s);
void foo_bar_delete(Bar b);
int foo_bar_property1(Bar b);
char const& foo_bar_property2(Bar b);
#ifdef __cplusplus__
}
#endif
随附的实施:
Bar foo_bar_new(int i, char const* s) {
return new Foo::Bar(i, s);
}
void foo_bar_delete(Bar b) {
delete static_cast<Foo::Bar*>(b);
}
int foo_bar_property1(Bar b) {
return static_cast<Foo::Bar*>(b)->property1();
}
char const* foo_bar_property2(Bar b) {
return static_cast<Foo::Bar*>(b)->property2().c_str();
}
Bar foo\u Bar\u new(int i,char const*s){
返回新的Foo::Bar(i,s);
}
无效foo\u bar\u删除(b栏){
删除静态_cast(b);
}
int foo_bar_物业1(bar b){
返回static_cast(b)->property1();
}
char const*foo_bar_property2(b栏){
返回static_cast(b)->property2().c_str();
}
两个主要优点是:
- 完整的C++代码,具有完全封装的数据和更强类型系统的所有优点
- 跨版本的二进制稳定性使C接口更容易实现
注意:例如,这就是Clang和LLVM处理C兼容性的方式。非常感谢@matthieu-m。这是一个非常明智的方法,你是对的。不幸的是,它要求C端使用访问器方法来获取/设置属性数据——这是我的用户不会接受的:-/@MarkAsbach:好吧,如果您愿意,您可以填写struct
,而不是void*
。。。但是,您不能使用结构强制执行不变量,二进制兼容性将流出窗口。