Ответ 1
Вы не можете напрямую ссылаться на конструктор, но вы можете создавать функции factory, которые выделяют и возвращают экземпляры вашего объекта, и вы можете записывать эти функции таким образом, чтобы определение предоставлялось на С++ (где возможно используйте "новый", чтобы выделить объект и использовать конструкторы С++), но вызываемый из C.
В заголовке вы должны написать:
#ifdef __cplusplus
# define EXTERNC extern "C"
# define NOTHROW noexcept
#else
# define EXTERNC
# define NOTHROW
#endif
/* Alias for your object in C that hides the implementation */
typedef void* mylibraryname_mytype_t;
/* Creates the object using the first constructor */
EXTERNC mylibraryname_mytype_t mylibraryname_create_mytype() NOTHROW;
/* Creates the object using the second constructor */
EXTERNC mylibraryname_mytype_t mylibraryname_create_mytype_with_int(int val) NOTHROW;
/* Frees the object, using delete */
EXTERNC void mylibraryname_free_mytype(mylibraryname_mytype_t obj) NOTHROW;
Затем в исходном файле С++ вы можете:
EXTERNC mylibraryname_mytype_t mylibraryname_create_mytype() NOTHROW {
try {
return static_cast<mylibraryname_mtype_t>(new MyType);
}
catch (...) {
return nullptr;
}
}
EXTERNC mylibraryname_mytype_t create_mytype_with_int(int val) NOTHROW {
try {
return static_cast<mylibraryname_mytype_t>(new MyType(val));
}
catch (...) {
return nullptr;
}
}
EXTERNC void mylibraryname_free_mytype(mylibraryname_mytype_t obj) NOTHROW {
try {
MyType* typed_obj = static_cast<MyType*>(obj);
delete typed_obj;
}
catch (...) {
// Ignore
}
}
Затем ваш C-код должен включать один и тот же заголовок и использовать определение из исходного файла С++ при привязке к сгенерированной библиотеке.
Обратите внимание, что приведенный выше код проглатывает исключения оптом. Для реального API вы должны предоставить способ указания ошибок вызывающему абоненту (например, путем возврата выделенного объекта через выходной параметр и возврата кода состояния) вместо того, чтобы просто подавлять их.
Изменить
Как отмечается в комментариях, "_t" является технически зарезервированным суффиксом (хотя вы должны быть в порядке, если ваши символы имеют префикс, который вряд ли будет использоваться стандартными библиотеками в будущем), поэтому просто убедитесь, что ваши символы включают в себя библиотеку имя в качестве префикса. Следует также отметить, что typedef, хотя и не требуется, предназначен для того, чтобы использовать объект более самодокументированным, чем необработанный "void *" повсюду.