lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Friday 30 September 2005 06:23 pm, Mildred wrote:
> Is it possible to have multiple inehritance with tolua++ w/o using
> syntax like:
> myobject.__parent__:mymethod()
> ?

I have not looked at tolua++ in a long time, but things used to be much more 
complicated than that. You have to be very careful with casting in the 
presence of multiple inheritance.  Consider this layout:

class A {
};

class B {
};

class Derived : public A, public B {
};


Most compilers will layout Derived in memory such that the part from class A 
comes before class B.

If you then instantiate a Derived object and reference it through a pointer to 
the base class B

Derived *object = new Derived();
B *base_obj = object;

"object" points to the beginning of the Derived class as a whole, but 
"base_obj" actually points to the beginning of B in the Derived class layout, 
not the beginning of the Derived class as a whole. This works, because the 
compiler is aware of the involved types and can correct the pointers with the 
appropriate offsets when you cast. 

The problem is that tolua uses void * pointers, which loses all type 
information. Tolua does a direct cast from void * to the object's actual type 
when necessary. If you have a tolua binding that takes a B * as an argument, 
things go haywire in a hurry:

local object = Derived:new()
do_something(object)

where the signature is
void do_something(B *object);

When the object is instantiated in Lua, you have a void * pointer to the 
beginning of Derived. In the tolua binding for the do_something function, 
this pointer is retrieved and directly cast from void * to B *.

*Oops.* Now the pointer of type B * actually points to the beginning of the 
object, instead of the middle where the B class actually is laid out. 

What needs to happen is this cast sequence:

void * -> Derived * -> B *,

so for safe multiple inheritance in tolua, any pointer must first be cast to 
the object's original type, and only then it is safe to cast to the base 
class type.

One way to solve this problem is to generate a bunch of cast functions, like 
this:

/* Function to cast properly from derived types to base types, */
/* even in the presence of multiple inheritance. */
#ifdef __cplusplus
 template<class Derived, class Base>
 void *tolua_do_cast(void *p)
{
 Derived *d = static_cast<Derived *>(p);
 return static_cast<Base *>(d);
}
#endif

Then you need to populate a table indexed by the derived/base class metatable 
pairs, and a pointer to the appropriate cast function as the values. Every 
time tolua casts a userdata object, it needs to look up the appropriate 
function, based on the object's actual type (which can be determined only at 
run time) and the target type, then call it to get the correct pointer.  It 
sure is messy, and also entails a slight performance hit. :-(

Anyway, I made such a modification to tolua 4, just so that it would not crash 
on data types that had hidden mix-in classes. If anyone is interested and 
thinks that they might be useful for tolua++ and lua 5, let me know, and I 
can make the changes available.

Regards
- Christian
-- 
Christian Vogler, Ph.D.
Research Scientist, Gallaudet Research Institute
http://gri.gallaudet.edu/~cvogler/