如何在C和C ++中设计具有并行接口的库

时间:2012-11-04 13:40:05

标签: c++ c namespaces derived-class interface-design

我当前的项目是一个中等大小的库,它同时具有C和C ++接口。它以我希望可以从C和C ++函数访问的单一数据类型为中心,因为我想鼓励第三方通过用任一语言编写函数来扩展库。

我知道C / C ++混合的基础知识(比较例如http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html)并提出了以下解决方案:

我的基本设计围绕在C中创建一个结构体,其中暴露了所有数据(这是我的C程序员所期望的)并从中派生出一个隐藏成员访问权限的类,希望能够更安全地访问C ++程序员的结构。问题来自派生:我想在C ++中使用名称空间并隐藏C接口。当然,C结构本身不能被隐藏(不依赖于PIMPL习语),但这对我来说没问题。

以下示例代码使用C和C ++" client"编译并运行时没有明显错误。程式。但是,我想知道这个解决方案是否有效或是否有更好的解决方案。

示例代码:

#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

1 个答案:

答案 0 :(得分:3)

实际上,另一种方法是使用数据隐藏技术在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();
}

两个主要优点是:

  • 完整的C ++代码,具有完全封装的数据和更强大的类型系统的所有优点
  • 在C接口中更容易实现跨版本的二进制稳定性

注意:这就是Clang和LLVM处理C兼容性的方式,例如。