为C库编写C ++包装器

时间:2010-05-03 21:14:50

标签: c++ c wrapper

我有一个遗留的C库,以OO类型的形式编写。典型的功能如下:

LIB *lib_new();
void lib_free(LIB *lib);
int lib_add_option(LIB *lib, int flags);
void lib_change_name(LIB *lib, char *name);

我想在我的C ++程序中使用这个库,所以我认为需要一个C ++包装器。 以上所有内容似乎都会映射到:

class LIB
{
    public:
         LIB();
         ~LIB();
         int add_option(int flags);
         void change_name(char *name);
...
};

我以前从来没有写过C ++的C ++包装器,也找不到很多关于它的建议。这是创建C ++ / C包装器的好/典型/明智的方法吗?

7 个答案:

答案 0 :(得分:6)

不需要C ++包装器 - 您只需从C ++代码中调用C函数即可。恕我直言,最好不要包装C代码 - 如果你想把它变成C ++代码 - 很好,但要做一个完整的重写。

实际上,假设您的C函数在名为myfuncs.h的文件中声明,那么在您的C ++代码中,您将希望包含它们:

extern "C" {
   #include "myfuncs.h"
}

以便在使用C ++编译器编译时为它们提供C链接。

答案 1 :(得分:5)

我通常只编写一个简单的RAII包装器而不是包装每个成员函数:

class Database: boost::noncopyable {
  public:
    Database(): handle(db_construct()) {
        if (!handle) throw std::runtime_error("...");
    }
    ~Database() { db_destruct(handle); }
    operator db_t*() { return handle; }
  private:
    db_t* handle;
};

使用类型转换运算符,它可以与C函数一起使用:

Database db;
db_access(db, ...);  // Calling a C function with db's type conversion operator

答案 2 :(得分:2)

我认为只有使用更简单的库才能编写包装器才有意义。在你的情况下,你没有必要传递一个LIB *,并且可能在堆栈上创建LIB对象,所以我认为这是一个改进。

答案 3 :(得分:2)

这通常是我接近它的方式。我也不会使用char *但是使用std :: string。

答案 4 :(得分:1)

本身不需要C ++包装器。没有什么能阻止你在代码中调用C函数。

答案 5 :(得分:1)

如果没有别的“Lib”

,我还会考虑将LIB重命名为更好的东西

更改名称可能是吸气剂设定者......

所以GetName(char *)SetName(char *)

然后看看将其更改为std :: string而不是char *,如果它的SetName(const std :: string name)它将接受char *作为参数。

即慢慢转向C ++主义

答案 6 :(得分:0)

假设C库的分配/释放实例为create_instancedestroy_instance,并且暴露了一个名为call_function的函数,并且没有提供用于深度复制实例的 API,这将起作用:

class Wrapper
{
public:
    Wrapper(): m_instance(create_instance(), destroy_instance) {}

    explicit operator bool() const
    {
        // null check
        return bool(m_instance);
    }

    void callFunction()
    {
        call_function(m_instance.get());
    }

private:
    std::unique_ptr<instance, decltype(&destroy_instance)> m_instance;
};