December 03, 2007 Faking constructors! An overview of object layout. | ||||
---|---|---|---|---|
| ||||
I can fake constructors so they work as long as you don't cast to interfaces. The way Walter has casting to interfaces is pretty clever. An object is laid out in memory like so: vtbl ptr guts The guts are laid out as follows: super.guts this.tupleof interface-0 interface-1... interface-n is a pointer to an Interface struct. (This seems to be the only way of accessing these structs.) Then, in order to cast something to interface n, you just increment the pointer to interface-n. The awkward part is finding if you can cast to a particular interface, since the interface array for each type doesn't contain the interfaces that base classes implement. You have to go through each interface that this class implements directly to see if they are or inherit from the target, and you have to repeat that for each base class up to Object. This means that, in order to fake constructors, you have to do something like: // (public domain) T create(T)() { void** _this = cast(void**)malloc(__traits(classInstanceSize, T)); *_this = T.classinfo.vtbl.ptr; setInterfaces(_this, T.classinfo); T ret = *cast(T*)&this; // gc.setTypeInfo might do this if (typeid(T).flags == 1) gc.hasPointers(_this); else gc.hasNoPointers(_this); // call constructor? return ret; } void setInterfaces(void** _this, ClassInfo type) { if (type.base !is null) { setInterfaces(_this, type.base); } foreach (iface; type.interfaces) { // This should work but doesn't: according to the spec, for an // interface, vtbl[0] is a ptr to the Interface struct, but it's // not, which means the only way to get the Interface ptr is by // using a constructor -- begging the question. auto ptr = iface.classinfo.vtbl[0]; *(_this + (iface.offset / (void*).sizeof)) = ptr; } } I had to reverse engineer this. Don't let this happen to you! Now that there exists <http://digitalmars.com/d/phobos/object.html>, you need never do this again! Just four easy payments of $19.95. Well, okay, the spec doesn't say straight out that Classinfo.interfaces only includes those immediately implemented by this class. Other than that, it's in the spec. I thought this might be useful, in case someone else is doing stuff with proxying objects and the like. |
Copyright © 1999-2021 by the D Language Foundation