如何设计一个C和C+中具有并行接口的库+; 我目前的项目是一个中型图书馆,它同时也有C和C++接口。它围绕着一个数据类型,我希望从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++的“客户端”程序没有明显错误。然而,我想知道这个解决方案是有效的还是有更好的解决方案 示例代码:

我了解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*
。。。但是,您不能使用
结构强制执行不变量,二进制兼容性将流出窗口。