Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call a C++ constructor from a C-File

I've imported this program, which is parsing a lot of complex text and it's written in C. My own project is written in C++.

I actually intended, that whenever the parser-algorithm has found one of the key-tags then a one (of many) constructor of my class should be called, so that I'll have a nice structure in the end of the txt, as a result of the parsing process.

Here's the problem: I learned OOP with Java and started C++ with this project, so I need a little help: how can I call a C++ constructor out of my C based parser file ? I already checked the internet, but either this question is too trivial or my intended solution is not working ;)

Thanks for any advises.

like image 617
user3085931 Avatar asked Jun 16 '14 06:06

user3085931


People also ask

Can you call a constructor directly?

No, you cannot call a constructor from a method. The only place from which you can invoke constructors using “this()” or, “super()” is the first line of another constructor.

Can we use constructor in C?

A Constructor in C is used in the memory management of C++programming. It allows built-in data types like int, float and user-defined data types such as class. Constructor in Object-oriented programming initializes the variable of a user-defined data type. Constructor helps in the creation of an object.

How do you call a main constructor in C++?

A constructor is automatically called when an object is created. It must be placed in public section of class. If we do not specify a constructor, C++ compiler generates a default constructor for object (expects no parameters and has an empty body).

Can we call constructor from method in C++?

A constructor can call methods, yes. A method can only call a constructor in the same way anything else can: by creating a new instance.


1 Answers

You can't invoke the constructor, directly, but you can create factory functions that allocate and return instances of your object, and you can write these functions such that the definition is provided in C++ (where it is possible to use "new" to allocate the object and use the C++ constructors) but callable from C.

In the header, you should write:

 #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;

Then in your C++ source file, you can do:

 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
   }
 }

Your C code should then be able to include the same header and use the definition from the C++ source file when linked against the generated library.

Note that the code above is swallowing exceptions wholesale. For a real API, you should provide a way of indicating errors to the caller (e.g. by returning the allocated object via an output parameter and returning a status code) rather than merely suppressing them.

Edit
As noted in the comments, "_t" is technically a reserved suffix (though you should be fine if your symbols have a prefix that is unlikely to be used by standard libraries in the future), so just make sure that your symbols include the library name as a prefix. It should also be noted that the typedef, though not required, is intended to make uses of the object more self-documenting than a raw "void*" all over the place.

like image 159
Michael Aaron Safyan Avatar answered Sep 24 '22 18:09

Michael Aaron Safyan