Given a pure C++ class:
class ICppA {
public:
virtual ~ICppA() {}
virtual double add(double v) = 0;
virtual double sub(double v) = 0;
virtual double get() = 0;
};
Are there ways to create implementations of this interface in plain C in clang and gcc?
I understand the C++ standard does not cover the vtable
structure, and I understand this may not be a good idea. I am looking for compiler specific, probably non-portable solutions.
The following works for MSVC, (but is not portable):
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;
}
[EDIT]
It seems like the code above will work on clang and gcc if the vtable
contains an extra pointer before the first method, i.e.
// 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
};
(I am still reading to figure out what that unknown
pointer is and if the solution then becomes reliable)