lundi 14 septembre 2015

Handling Inherited C++ Functions in a C Binding

In short, I am maintaining a C-style binding (for other languages to call) around a C++ library (CSFML if anyone is curious). I was unable to find any other questions on this topic so please excuse me if I missed anything.

My question centers on the fact that C-style functions have no concept of inheritance. So the current practice in the library is to duplicate every function for each derived type. This very quickly leads to impossible to maintain code. Let me give an example...

// This is your basic C++ OOP inheritance.
struct Foo
{
  void Multiply();
};

struct Bar : Foo
{
  void Divide();
};

struct Child : Bar
{
  void Exp();
};

// Now if we were to write C-style functions to wrap the above code
// (leaving out create/destroy functions for clarity)

// C-style apis wrap their data with internal structs
// and only expose pointers to them
typedef struct FooStruct FooStruct;
typedef struct FooStruct BarStruct;
typedef struct FooStruct ChildStruct;

void Foo_Multiply(FooStruct* Instance);

void Bar_Multiply(BarStruct* Instance);
void Bar_Divide(BarStruct* Instance);

void Child_Multiply(ChildStruct* Instance);
void Child_Divide(ChildStruct* Instance);
void Child_Exp(ChildStruct* Instance);

// Notice how the inherited functions are duplicated
// for each level of the inheritance hierarchy?

From the above code you can see how each level of inheritance requires the C-style functions to duplicate each and every function so that calling code can access the functions they need. You can imagine with deep hierarchies or many functions even with a small hierarchy this quickly leads to code that can not be easily maintained.

I have also tried the following pattern of providing a function that returns a pointer to the base class that would allow derived types to call base class functions without duplicating each function.

// (continued from above, excluding duplicated functions)

FooStruct* Bar_GetBase(BarStruct* Instance);
BarStruct* Child_GetBase(ChildStruct* Instance);

// And it would be used as following...
ChildStruct* child; // == a valid Child pointer
BarStruct* childBar = Child_GetBase(child);

Bar_Divide(childBar);

This method works to an extent (it makes memory management quit harder), so I am looking for any alternatives.

So my question can be summed up in the following: What are some ways to wrap inherited functions in a C-style bindings without duplicating each function?

Aucun commentaire:

Enregistrer un commentaire