Last active
October 5, 2020 09:46
-
-
Save andreafioraldi/40d393b80635832da74a612e90596cbc to your computer and use it in GitHub Desktop.
C to C++ and back
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#define offsetof(type, field) ((size_t)&(((type *)0)->field)) | |
#define derived_cast(derived_type, obj) ((derived_type*)((char*)(obj) - offsetof(derived_type, base))) | |
/// BASE | |
struct base_C_class; | |
struct base_C_funcs { | |
void (*print)(struct base_C_class*); | |
}; | |
struct base_C_class { | |
void* wrapper; // base classes need to have this field instead of the base field | |
struct base_C_funcs funcs; | |
int info; | |
}; | |
void base_C_class_print(struct base_C_class* self) { | |
printf("base_C_class_print %d\n", self->info); | |
} | |
void base_C_class_init(struct base_C_class* self, int info) { // contructor | |
self->funcs.print = &base_C_class_print; | |
self->info = info; | |
} | |
struct base_C_class* create_base_C_object(int info) { | |
struct base_C_class* o = (struct base_C_class*)malloc(sizeof(struct base_C_class)); | |
base_C_class_init(o, info); | |
return o; | |
} | |
/// DERIVED : BASE | |
struct derived_C_class; | |
struct drived_C_funcs { | |
void (*change_info)(struct derived_C_class*, int); | |
}; | |
struct derived_C_class { | |
struct base_C_class base; // derived classes need to have this field instead of the wrapper field | |
struct base_C_class* objptr; | |
struct drived_C_funcs funcs; | |
}; | |
void derived_C_class_print(struct base_C_class* self) { | |
struct derived_C_class* d_self = derived_cast(struct derived_C_class, self); | |
printf("derived_C_class %d\n", d_self->base.info); | |
} | |
void derived_C_class_change_info(struct derived_C_class* self, int info) { | |
self->base.info = info; | |
} | |
void derived_C_class_init(struct derived_C_class* self, int info) { // contructor | |
base_C_class_init(&self->base, info); | |
self->base.funcs.print = &derived_C_class_print; | |
} | |
struct derived_C_class* create_derived_C_object(int info) { | |
struct derived_C_class* o = (struct derived_C_class*)malloc(sizeof(struct derived_C_class)); | |
derived_C_class_init(o, info); | |
return o; | |
} | |
/// C++ BASE | |
class Base { | |
protected: | |
struct base_C_class* bind; | |
void register_binding(); | |
Base(struct base_C_class* from_c) { | |
bind = from_c; | |
bind->wrapper = static_cast<void*>(this); | |
register_binding(); // just the base funcs | |
} | |
public: | |
static Base* from_c_instance(struct base_C_class* obj) { | |
if (obj->wrapper) | |
return (Base*)obj->wrapper; | |
return new Base(obj); | |
} | |
struct base_C_class* to_c_instance() { // back to C | |
return bind; | |
} | |
Base(int info) : Base(create_base_C_object(info)) {} | |
virtual void print() { | |
base_C_class_print(bind); | |
} | |
// define getters/setters of fields | |
int get_info() { | |
return bind->info; | |
} | |
int set_info(int info) { | |
bind->info = info; | |
} | |
}; | |
void Base::register_binding() { | |
bind->funcs.print = [](struct base_C_class* self) -> void { | |
Base* obj = static_cast<Base*>(self->wrapper); | |
obj->print(); // rely on the C++ class vtable | |
}; | |
} | |
/// C++ DERIVED | |
class Derived : public Base { | |
protected: | |
Derived(struct derived_C_class* from_c) : Base((struct base_C_class*)from_c) { | |
// just the derived funcs | |
struct derived_C_class* d_bind = (struct derived_C_class*)bind; | |
d_bind->funcs.change_info = [](struct derived_C_class* self, int info) -> void { | |
Derived* obj = static_cast<Derived*>(self->base.wrapper); | |
obj->change_info(info); // rely on the C++ class vtable | |
}; | |
} | |
public: | |
static Derived* from_c_instance(struct derived_C_class* obj) { | |
if (obj->base.wrapper) | |
return (Derived*)obj->base.wrapper; | |
return new Derived(obj); | |
} | |
struct derived_C_class* to_c_instance() { // back to C | |
return (struct derived_C_class*)bind; | |
} | |
Derived(int info) : Derived(create_derived_C_object(info)) {} | |
virtual void print() { | |
derived_C_class_print(bind); | |
} | |
virtual void change_info(int info) { | |
derived_C_class_change_info((struct derived_C_class*)bind, info); | |
} | |
Base* get_objptr() { | |
return Base::from_c_instance(((struct derived_C_class*)bind)->objptr); | |
} | |
}; | |
/// C++ ONLY DERIVED SECOND CLASS | |
class CppDerived : public Base { | |
const char* str; | |
public: | |
CppDerived(const char* name, int info) : Base(info), str(name) {} // here we call the right constructor | |
virtual void print() { | |
printf("hello %s from C++ %d\n", str, get_info()); | |
} | |
}; | |
int main() { | |
Derived d(666); | |
d.print(); | |
struct base_C_class* dc = (struct base_C_class*)d.to_c_instance(); | |
dc->funcs.print(dc); | |
Base * b = &d; | |
b->print(); | |
CppDerived cpp("andrea", 123); | |
cpp.print(); | |
struct base_C_class* cppc = cpp.to_c_instance(); | |
cppc->funcs.print(cppc); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Notes:
In C vtable, add a create_wrapper entry that is an hook registered by the wrapper. In C++, do something like from_c(cptr) in which from_c creates an instance of Derived and cast it or return wrapper if any.
create a vtable too for C++ drived only classes in which the create_wrapper thing just return wrapper