What you want is to "un-objectify" the functions.
Every public function that is inside a class has to be created outside with the first parameter void*
and the rest of the parameters the same as in the member function.
This means you also have to create a "constructor" and a "destructor" function for the object.
There are 2 ways these functions can work, depending or where the data is to be stored: memory provided by the caller or memory allocated by the library (on the "free store").
The first thing that the new functions need is to declare linkage https://en.cppreference.com/w/cpp/language/language_linkage
Only two language linkages are guaranteed to be supported:
- "C++", the default language linkage.
- "C", which makes it possible
to link with functions written in the C programming language, and to define, in a C++ program, functions that can be called from the modules written in C.
So in the new header when it is used in C++ the linkage has to be declared, but when the header is used in C the linkage has to be removed:
So this is needed at the beginning:
#ifdef __cplusplus
extern "C"
{
#endif
and at the end:
#ifdef __cplusplus
}
#endif
Memory allocated on the "free store".
The declaration of the functions in the header within the above code should be:
void* childA_construct(); // ChildA doesn't have and constructor paramters
void* childA_destruct();
void* childB_construct(void* ptr_childA);
void* childB_destruct();
void* parentB_construct(); // parentB doesn't have and constructor paramters
void* parentB_destruct();
bool parentB_Init(struct MyType m);
Next in the implementation file:
extern "C"
{
void* childA_construct()
{
return static_cast< void* >(new childA());
}
void childA_destruct(void* ptr_childA)
{
delete static_cast< childA* >(ptr_childA);
}
void* childB_construct(void* ptr_childA)
{
childA* a_ptr = static_cast< childA* >(ptr_childA);
return static_cast< void* >(new childB(a_ptr));
}
void childB_destruct(void* ptr_childB)
{
delete static_cast< childB* >(ptr_childB);
}
void* parentB_construct()
{
return static_cast< void* >(new parentB());
}
void* parentB_destruct(void* ptr_parentB)
{
delete static_cast< parentB* >(ptr_parentB);
}
bool parentB_Init(void* ptr_parentB, struct MyType mt)
{
parentB* ptr_pb = static_cast< parentB* >(ptr_parentB);
return ptr_pb->Init(mt);
}
}
Memory allocated by caller
If the interface requires that the caller allocates memory, then the caller needs to know how much memory to allocate, so one way is to make a function return the required size.
Then in the construct method "placement new" has to be used to call the constructor.
While in the destruct function, the destructor has to be called manually.
extern "C"
{
int sizeof_childA() { return sizeof(childA); }
void childA_construct2(void* ptr_buffer) { new (ptr_buffer)childA(/*constructor params*/); }
void childA_destruct2(void* ptr_buffer) { static_cast< childA* >(ptr_buffer)->~childA(); }
}
If you want to store and use function pointer for C, then to declare a function type:
extern "C" typedef unsigned MyFuncType(struct Msg*);
then the variable can stored as:
MyFuncType func;