'Implementing a C++ (pure) interface using plain C

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.

Example for MSVC

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)



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source