Writing a C++ wrapper for a C library
I have a legacy C library, 开发者_开发技巧written in an OO type form. Typical functions are like:
LIB *lib_new();
void lib_free(LIB *lib);
int lib_add_option(LIB *lib, int flags);
void lib_change_name(LIB *lib, char *name);
I'd like to use this library in my C++ program, so I'm thinking a C++ wrapper is required. The above would all seem to map to something like:
class LIB
{
public:
LIB();
~LIB();
int add_option(int flags);
void change_name(char *name);
...
};
I've never written a C++ wrapper round C before, and can't find much advice about it. Is this a good/typical/sensible approach to creating a C++/C wrapper?
A C++ wrapper is not required - you can simply call the C functions from your C++ code. IMHO, it's best not to wrap C code - if you want to turn it into C++ code - fine, but do a complete re-write.
Practically, assuming your C functions are declared in a file called myfuncs.h then in your C++ code you will want to include them like this:
extern "C" {
#include "myfuncs.h"
}
in order to give them C linkage when compiled with the C++ compiler.
I usually only write a simple RAII wrapper instead of wrapping each member function:
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;
};
With the type conversion operator this can be used with the C functions:
Database db;
db_access(db, ...); // Calling a C function with db's type conversion operator
I think it only makes sense to write a wrapper if it makes the use of the library simpler. In your case, you're making it unnecessary to pass a LIB* around, and presumably it will be possible to create LIB objects on the stack, so I'd say this is an improvement.
That's generally how I would approach it. I would also not use char* but use std::string.
A C++ wrapper is not needed per se. There's nothing stopping you from calling the C functions in your code.
I'd also look at renaming LIB to something a bit better, if nothing else "Lib"
Change Name is likely to be a getter setter...
so GetName(char *) SetName(char *)
and then look at changing it to std::string instead of char*, if its SetName(const std::string name) it will accept a char* as a parameter.
ie, slowly move to C++isms
Assuming that the C library's allocation/deallocation instances are create_instance and destroy_instance, and it exposes a function called call_function, and it does not provide an API for deep copying instances, this will work:
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;
};
精彩评论