bcd.gen: A generator for bindings to C++ in D
Gregor Richards
Richards at codu.org
Wed Jun 7 08:43:52 PDT 2006
Bruno Medeiros wrote:
> Gregor Richards wrote:
>
>> It is now possible to derive D classes from C++ classes in
>> bcd.gen-generated bindings.
>
>
> Whoa, how is that possible? Wait, better yet could you clarify me a bit
> more on what exactly is "derive D classes from C++ classes" first? And
> perhaps give an example?
Sure!
First, the transparent programmer's perspective:
C++ code:
{{
class A {
virtual void foo();
virtual int bar(int);
}
}}
Generated D code:
{{
class A {
void foo() { ... }
int bar(int) { ... }
}
class A_R {
this() { /* very extra-special constructor stuff here */ }
}
}}
To derive a D class from the C++ class A:
{{
class MyClass : A_R {
void foo() {
// whatever you want
}
}
}}
Now, if you pass a MyClass as an A (which is valid because it's derived
from it), foo will be overridden, and the C++ calls to foo will hit your
foo, not C++'s!
Now, the nasty internals:
Supplied C++ code:
{{
class A {
virtual void foo();
virtual int bar(int);
}
}}
Generated C++ code:
{{
extern "C" int __BCD_CHECK_A_foo(void *);
extern "C" void __BCD_A_foo(void *);
extern "C" int __BCD_CHECK_A_bar(void *);
extern "C" int __BCD_A_bar(void *, int);
/* the names above are actually generated unique names */
class __A_DRefelction {
/* this is actually a name which is generated and guaranteed to be unique */
void foo() {
if (__BCD_CHECK_A_foo(__D_data)) {
__BCD_A_foo(__D_data);
} else {
A::foo();
}
}
int bar(int _1) {
if (__BCD_CHECK_A_bar(__D_data)) {
return __BCD_A_bar(__D_data, _1);
} else {
return A::bar(_1);
}
}
}
}}
Notes:
1) __D_data is set by the D constructor
2) __BCD_CHECK_* are functions implemented in D to check whether a
particular method has been overridden in a D class or not.
3) __BCD_* are generated wrapper functions to the D methods.
Generated D code:
{{
class A {
void foo() { ... }
int bar(int) { ... }
}
class A_R {
this() { /* very extra-special constructor stuff here */ }
}
extern (C) int __BCD_CHECK_A_foo(A_R This) {
/* this is a simplification of the real, overcomplicated code */
return cast(int) (This.foo != A_R.foo);
}
extern (C) void __BCD_A_foo(A_R This) {
This.foo();
}
extern (C) int __BCD_CHECK_A_bar(A_R This) {
/* again, a simplification */
return cast(int) (This.bar != A_R.bar);
}
extern (C) int __BCD_A_bar(A_R This, int _1) {
return This.bar(_1);
}
}}
Basically, in English:
For every class in C++, a class is made which overrides every virtual
function with checks into D. If it's not overridden by D, it calls the
lower virtual function (just like it would do if it wasn't overridden at
all).
For every class in D, a class is made which, rather than generating the
base C++ class, generates the previously-mentioned reflection class (the
reason for not doing this as the general case is efficiency)
For every virtual function, a wrapper is made in D to check whether that
function has been overridden in a D class.
I'm not sure if that helped at all. Hopefully it did :)
>
> (sorry if I'm being a bit lazy to look it up myself)
>
The code is very ugly ... probably wiser just to ask ;)
- Gregor Richards
PS: For those that are interested about progress:
wxWidgets uses method pointers. I'm not sure if I can bind these, as
they're very inconsistent in C++.
I haven't actually tried to bind Qt yet, but it's more promising than
wxWidgets.
More information about the Digitalmars-d-announce
mailing list