То, что вы хотите, это «не объективировать» функции.
Каждая открытая функция, которая находится внутри класса, должна создаваться снаружи с первым параметром void*
, а остальные параметры должны быть одинаковыми.как в функции-члене.
Это означает, что вам также нужно создать функцию «конструктор» и «деструктор» для объекта.
Существует два способа работы этих функций в зависимости от того, где хранятся данные: память, предоставляемая вызывающим абонентом, или память, выделенная библиотекой (в «free store» ).
Первое, что нужно новым функциям - это объявить связь https://en.cppreference.com/w/cpp/language/language_linkage
Гарантируется, что поддерживаются только две языковые связи:
- "C ++", языковая связь по умолчанию.
- «C», что позволяет связывать с функциями, написанными на языке программирования C, и определять в программе на C ++ функции, которые можно вызывать из модулей, написанных на C.
Таким образом, в новом заголовке, когда он используется в C ++, должна быть объявлена связь, но когда заголовок используется в C, связь должна быть удалена:
Так что этонеобходимо в начале:
#ifdef __cplusplus
extern "C"
{
#endif
и в конце:
#ifdef __cplusplus
}
#endif
Память, выделенная в «свободном хранилище».
ОбъявлениеФункции в заголовке в приведенном выше коде должны быть:
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);
Далее в файле реализации:
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);
}
}
Память, выделенная вызывающей стороной
ЕслиИнтерфейс требует, чтобы вызывающая сторона выделяла память, а затем вызывающая сторона должна знать, какой объем памяти выделить, поэтому один из способов - заставить функцию вернуть требуемый размер.
Затем в методе конструкции «размещение нового» необходимоиспользоваться для вызова конструктора.
Находясь в функции destruct, деструктор должен вызываться вручную.
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(); }
}
Если вы хотите сохранить и использовать указатель функции для C, то для объявления типа функции:
extern "C" typedef unsigned MyFuncType(struct Msg*);
тогда переменная может храниться как:
MyFuncType func;