Dada una clase C++ pura:
class ICppA { public: virtual ~ICppA() {} virtual double add(double v) = 0; virtual double sub(double v) = 0; virtual double get() = 0; };
¿Hay formas de crear implementaciones de esta interfaz en C simple en clang y gcc?
Entiendo que el estándar C++ no cubre la estructura vtable
, y entiendo que esto puede no ser una buena idea. Estoy buscando soluciones específicas del compilador, probablemente no portátiles.
Lo siguiente funciona para MSVC (pero no es portátil):
typedef struct CA CA; // The plain C vtable struct CA_VTable { void (*dtor)(CA*); double (*add)(CA*, double v); double (*sub)(CA*, double v); double (*get)(CA*); }; // The plain C implementation struct CA { CA_VTable* _vtable; double total; }; void CA_DTor(CA*) {} double CA_Add(CA* o, double v) { return (o->total += v); } double CA_Sub(CA* o, double v) { return (o->total -= v); } double CA_Get(CA* o) { return o->total; } // Create a static vtable that all instances can use static CA_VTable _CA_VTable = { CA_DTor, CA_Add, CA_Sub, CA_Get }; void CA_CTor(CA* ca) { ca->_vtable = &_CA_VTable; ca->total = 0; }
void testA(ICppA* a) { std::cout << "initial value: " << a->get() << std::endl; std::cout << "add 5: " << a->add(5) << std::endl; std::cout << "sub 2: " << a->sub(2) << std::endl; } int main() { CA ca; CA_CTor(&ca); testA((ICppA*)&ca); CA_DTor(&ca); return 0; }
[EDITAR] Parece que el código anterior funcionará en clang y gcc si vtable
contiene un puntero adicional antes del primer método, es decir
// The plain C vtable struct CA_VTable { void* unknown; void (*dtor)(CA* self); double (*add)(CA* self, double v); double (*sub)(CA* self, double v); double (*get)(CA* self); }; [...] // Create a static vtable that all instances can use static CA_VTable _CA_VTable = { nullptr, CA_DTor, CA_Add, CA_Sub, CA_Get };
(Todavía estoy leyendo para averiguar qué es ese puntero unknown
y si la solución se vuelve confiable)