3 ms·
Indeed. It's super easy to create an opaque type in C: forward-declare a struct. So in the header: struct Rational2; struct Rational2 *make_rational(in
by tom_ 3y ago
Indeed. It's super easy to create an opaque type in C: forward-declare a struct. So in the header:
struct Rational2;
struct Rational2 *make_rational(int,int);
Then in the file:
Rational2 *make_rational(int n,int d){
return (Rational2 *)new Rational(n,d);
}
void del_rational(Rational2 **pp){
delete (Rational2 *)*pp;
*pp=nullptr;
}
And so on. You could probably arrange for it to be called Rational in both languages, starting out along these lines and then taking it from there:
#ifdef __cplusplus
class Rational { ... };
#else
struct Rational;
typedef struct Rational Rational;
#endif
And now you can could your C helpers from C++ as well, and the result is a genuine C++ Rational object that you can use either way. I don't think the ODR applies across languages, and I'm not 100% certain this would actually be an ODR violation anyway, at least not quite, but you'd need to ask somebody more qualified than me.
(Another suggestion I would have is to bracket the entire header in the ifdef'd extern "C" {...} block, which limits the amount of extra crap you have in the header and per function. I think you can direct clang-format not to indent these blocks.)
- zabzonk 3y agoit's super easy to define an opaque type in c++ - you do it just like you do in c. you don't need to jump through these hoops.
- tom_ 3y agoQuite. And in fact, in this specific situation, in C++ you don't need to jump through any hoops at all, because you have the Rational class there already, ready for use. This whole business only exists to provide a C-friendly wrapper for this existing C++ class, along the lines of the one proposed in the article, with a couple of tweaks that I think would improve it.
- gpderetta 3y agoThe converse is that if your class is just a standard layout object with a trivial destructor, you can expose an equivalent C definition without all the C++ sugar and avoid the forced allocation. The allocation and the opaque handler can still be useful for ABI stability purposes, but that's true in C++ as well.