我有一个遗留的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包装器的好/典型/明智的方法吗?
答案 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_instance和destroy_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;
};