You might get something close to virtual functions:
// With apologies to Doug, for borrowing his code
class X
{
public:
X();
virtual void f();
};
class Y : public X
{
public:
Y();
virtual void f();
};
// C interface
#ifdef __cplusplus
extern "C" {
#endif
// Type-safe, opaque pointer.
typedef struct C_X_* X_Handle;
typedef struct C_Y_* Y_Handle;
// Export these using __declspec, for example
X_Handle CreateX();
void DestroyX(X_Handle x);
Y_Handle CreateY();
void DestroyY(Y_Handle y);
void X_f(X_Handle x);
void Y_f(Y_Handle y);
#ifdef __cplusplus
}
#endif
// C++ implementation
X_Handle CreateX()
{
return reinterpret_cast<X_Handle>(new X);
}
void DestroyX(X_Handle x)
{
delete reinterpret_cast<X*>(x);
}
void X_f(X_Handle x)
{
reinterpret_cast<X*>(x)->f();
}
Y_Handle CreateY()
{
return reinterpret_cast<Y_Handle>(new Y);
}
void DestroyY(Y_Handle y)
{
delete reinterpret_cast<Y*>(y);
}
void Y_f(Y_Handle y)
{
reinterpret_cast<Y*>(y)->f();
}
So far, so good. If we have an X object, we can use the CreateX, DestroyX
and X_f functions; and if we have a Y object, we can use the CreateY,
DestroyY and Y_f functions. But to truly get the "virtual" part going, we
would need to do something like this and have it work:
Y_Handle y = CreateY();
X_f(y); // if this is really virtual, it will call the Y object's version of
f.
But here's the problem: The first parameter of X_f must be of type X_Handle
(really type C_X_*). But the variable y is of type Y_Handle (or type C_Y_*).
Therefore, the code X_f(y) won't compile, because the types don't match, and
there is no implicit conversion from C_Y_* to C_X_*.
Something like X_f(reinterpret_cast<X_Handle>(y)) might do it, though. I'd
give it a shot. Presumably the y variable, which has type C_Y_* would first
be cast to type X_Handle (or C_X_*), then cast again to type X* inside the
X_f function. Then the program would see a pointer to an X object try to
select its member f function. Since y really points to a Y object, and f is
virtual, you would theoretically get Y's version of f.
Even if it doesn't work, you'll learn something about just how far you can
cast a pointer before it breaks.
Sean