Search code examples
c++cwrapper

Developing C wrapper API for Object-Oriented C++ code


I'm looking to develop a set of C APIs that will wrap around our existing C++ APIs to access our core logic (written in object-oriented C++). This will essentially be a glue API that allows our C++ logic to be usable by other languages. What are some good tutorials, books, or best-practices that introduce the concepts involved in wrapping C around object-oriented C++?


Solution

  • This is not too hard to do by hand, but will depend on the size of your interface. The cases where I've done it were to enable use of our C++ library from within pure C code, and thus SWIG was not much help. (Well maybe SWIG can be used to do this, but I'm no SWIG guru and it seemed non-trivial)

    All we ended up doing was:

    1. Every object is passed about in C an opaque handle.
    2. Constructors and destructors are wrapped in pure functions
    3. Member functions are pure functions.
    4. Other builtins are mapped to C equivalents where possible.

    So a class like this (C++ header)

    class MyClass
    {
      public:
      explicit MyClass( std::string & s );
      ~MyClass();
      int doSomething( int j );
    }
    

    Would map to a C interface like this (C header):

    struct HMyClass; // An opaque type that we'll use as a handle
    typedef struct HMyClass HMyClass;
    HMyClass * myStruct_create( const char * s );
    void myStruct_destroy( HMyClass * v );
    int myStruct_doSomething( HMyClass * v, int i );
    

    The implementation of the interface would look like this (C++ source)

    #include "MyClass.h"
    
    extern "C" 
    {
      HMyClass * myStruct_create( const char * s )
      {
        return reinterpret_cast<HMyClass*>( new MyClass( s ) );
      }
      void myStruct_destroy( HMyClass * v )
      {
        delete reinterpret_cast<MyClass*>(v);
      }
      int myStruct_doSomething( HMyClass * v, int i )
      {
        return reinterpret_cast<MyClass*>(v)->doSomething(i);
      }
    }
    

    We derive our opaque handle from the original class to avoid needing any casting, and (This didn't seem to work with my current compiler). We have to make the handle a struct as C doesn't support classes.

    So that gives us the basic C interface. If you want a more complete example showing one way that you can integrate exception handling, then you can try my code on github : https://gist.github.com/mikeando/5394166

    The fun part is now ensuring that you get all the required C++ libraries linked into you larger library correctly. For gcc (or clang) that means just doing the final link stage using g++.