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