Why should non-POD types in C++ be opaque to C clients?
gcc 4.4.4 c89
I was just reading a discussion at DevX about calling C++ code from C since I have to do s开发者_运维知识库omething similar. I am just wondering what user Vijayan meant by "make sure that non POD types in C++ are opaque to C clients."
Many thanks for any suggestions,
C can only deal with POD types.
Consequently, you cannot pass objects of non-POD types to C programs (by value). Also, if you pass pointers of non-POD types to C programs, they can't interact with the objects pointed to.
POD = Plain old data structure = C structs, no virtual methods, etc. You need to write wrapper functions for C to access non-POD types (i.e., classes).
More on POD: http://en.wikipedia.org/wiki/Plain_old_data_structure
For a type to be opaque means you can't look inside it: it's a "black box" that can be passed around but not inspected or manipulated directly by the C code. You typically refer to the object using either heap-allocated memory and void*s, or using functions to determine the necessary length and buffers.
For example, a C++ object might contain a std::string
, but the layout of a std::string
is not specified in the C++ Standard, so you can't write C code that directly reads from or writes to the string (at least, not without having a total understanding of the std::string
layout, manually revalidated every time the compiler/STL is updated).
So, to allow C code to access the object, you might write C-callable functions such as:
#if __cplusplus
extern "C" {
#endif
void* object_new();
const char* object_get_string(void* p_object);
void object_set_string(void* p_object, const char* s);
void object_delete();
#if _cplusplus
}
#endif
With C++ implementation ala:
class Object { std::string string_; ... }
void* object_new() { return new Object; }
const char* object_get_string(void* p) { return ((Object*)p)->string_.c_str()); }
...
Here, the object_XXX functions provide the C code with a safe way to use the Object.
Making the type opaque means, as per the line in the link:
typedef struct base base ; /* opaque */
makes the name of the handle available to C code, but not the definition of the type. This means that the C code cannot access any members directly, but has to go through the interface functions.
Note that you do not have to make a cast to a generic , i.e. void*, pointer, although doing so is one option, as per 9dan's answer.
Note that such a style of interface is in my experience a very nice way to manage encapsulation even in pure C code, just as in the standard C streams library.
Making opaque to clients means nothing special. C stream file I/O (FILE* f = fopen
) API is the typical example that present opaque handle to clients.
Apparently C can not handle non-POD type so you must hide C++ implementation from C clients but provide access method.
Example:
C++ Implementation
class MyLibrary {
MyLibrary();
~MyLibrary();
int DoSomething();
...
}
Declaration for C clients
typedef void* OPAQUEHANDLE;
extern OPAQUEHANDLE MyLibrary_OpenLibrary();
extern void MyLibrary_CloseLibrary(OPAQUEHANDLE h);
extern int MyLibrary_DoSometing(OPAQUEHANDLE h);
Implementation for C clients (in .cpp file)
extern OPAQUEHANDLE MyLibrary_OpenLibrary()
{
return new MyLibrary;
}
extern void MyLibrary_CloseLibrary(OPAQUEHANDLE h)
{
delete (MyLibrary*) h;
}
extern int MyLibrary_DoSometing(OPAQUEHANDLE h)
{
return ((MyLibrary*)h)->DoSomething();
}
精彩评论