Вопрос по constructor, import, c, c++, oop – Как вызвать конструктор C ++ из C-File

18

Я импортировал эту программу, которая анализирует много сложного текста и написана на C. Мой собственный проект написан на C ++.

Я действительно хотел, чтобы всякий раз, когда алгоритм синтаксического анализа обнаружил один из ключевых тегов, должен вызываться один (из многих) конструктор моего класса, так что в конце txt у меня будет хорошая структура, так как результат процесса разбора.

Вот проблема: Я изучил ООП с Java и запустил C ++ с этим проектом, поэтому мне нужна небольшая помощь: как я могу вызвать конструктор C ++ из моего файла парсера на основе C? Я уже проверил интернет, но или этот вопрос слишком тривиален, или мое намеченное решение не работает;)

Спасибо за любые советы.

Я думаю, что если вы скомпилируете с помощью компилятора c ++ и включите определение своего класса в файл c, это сработает? Ты пробовал? Это будет просто, как если бы все было на C ++, но вы использовали внутри него C, кто-то работает. user1585121
@deviantfan Да, я должен признать, что я был сбит с толку, когда писал свой комментарий, я всегда думал, что интеграция c внутри c ++ была тривиальной. То, как я научился использовать C, работает в C ++, я не помню больших проблем. user1585121
Хорошо, глядя на ответ Михаэля, я, должно быть, ошибаюсь, зная это :) user1585121
@deviantfan парсер довольно сложный и недокументированный, я действительно не хочу ничего трогать, если у меня нет другого шанса user3085931

Ваш Ответ

1   ответ
23

но вы можете создать фабричные функции, которые размещают и возвращают экземпляры вашего объекта, и вы можете написать эти функции так, чтобы определение было предоставлено в C ++ (где можно использовать «new» для выделить объект и использовать конструкторы C ++), но можно вызывать из 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;

Затем в исходном файле C ++ вы можете сделать:

 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 должен затем иметь возможность включать тот же заголовок и использовать определение из исходного файла C ++ при связывании с созданной библиотекой.

Обратите внимание, что код выше глотает исключения оптом. Для реального API вы должны предоставить способ указания ошибок вызывающей стороне (например, путем возврата выделенного объекта через выходной параметр и возврата кода состояния), а не просто подавлять их.

редактировать
Как отмечалось в комментариях, «_t» технически является зарезервированным суффиксом (хотя вам должно быть хорошо, если ваши символы имеют префикс, который вряд ли будет использоваться стандартными библиотеками в будущем), поэтому просто убедитесь, что ваши символы включают библиотеку имя в качестве префикса. Следует также отметить, что typedef, хотя и не требуется, предназначен для того, чтобы сделать использование объекта более самодокументированным, чем необработанный «void *» повсюду.

Хороший звонок, @MatsPetersson. Я обновлю, чтобы включить "noexcept". Michael Aaron Safyan
Ага. Это неопределенное поведение. Насколько я понимаю, "noexcept" заставит компилятор C ++ вставлять вызов terminate (), а не распространять исключение из функции. Michael Aaron Safyan
Зарезервировано стандартом ISO C. Это задокументировано в документации glibc:gnu.org/software/libc/manual/html_node/Reserved-Names.html Michael Aaron Safyan
Тип является классом C ++, поэтому нецелесообразно вводить определение фактической структуры (и даже если бы это было так, полезно скрывать ради инкапсуляции). Michael Aaron Safyan

Похожие вопросы