1

我当前的项目是一个中型库,旨在同时具有 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++“客户端”程序中编译和运行时没有明显错误。但是,我想知道这个解决方案是否有效或者是否有更好的解决方案。

示例代码:

#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
4

1 回答 1

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 兼容性的方式。

于 2012-11-04T14:15:26.387 回答