Implementing Virtual Methods With Toluapp |
|
2 files are needed:
Files:wiki_insecure/users/ArielManzur/tolua++/virtual_method_hooks.lua
Files:wiki_insecure/users/ArielManzur/tolua++/tolua_base.h
Create a .pkg file
// mypackage.pkg $#include "tolua_base.h" class Widget { protected: virtual bool input_event(Event* e); public: virtual void add_child(Widget* child); void close(); Widget(string p_name); };
Generate the package
tolua++ -L virtual_method_hooks.lua mypackage.pkg > mypackage.cpp (compile 'mypackage.cpp' with the rest of the code)
Use the class Lua__Widget from your lua script
-- custom_widget.lua require "mypackage" local CustomWidget = {} CustomWidget.__index = CustomWidget function CustomWidget:input_event(e) if e.type = Event.KEY_PRESS and e.key_code == KEY_ESCAPE then -- close the widget when escape is pressed self:close() return true end -- call Widget::input_event return self:Widget__input_event(e) end function CustomWidget:new(name) -- create a table and make it an 'instance' of CustomWidget local t = {} setmetatable(t, CustomWidget) -- create a Lua__Widget object, and make the table inherit from it local w = Lua__Widget:new(name) tolua.setpeer(w, t) -- use 'tolua.inherit' on lua 5.0 -- 'w' will be the lua object where the virtual methods will be looked up w:tolua__set_instance(w) return w -- return 't' on lua 5.0 with tolua.inherit end
In this example, the class 'Lua__Widget' is generated. Lua__Widget has all the constructors of Widget, and a method 'tolua__set_instance', to provide the lua object where the virtual methods will be looked up (in this case, we use the same userdata object used for the c++ object, because our lua functions override the c++ functions). This object will be passed as self
on the lua methods. Lua__Widget also exposes the virtual methods from Widget to be called directly.
A subclass that inherits from a class with virtual methods will also generate code to implement those methods from lua, but only if the subclass has any virtual methods itself. For example, if we add the following to our pkg:
class Label : public Widget { public: void set_text(string p_text); };
this will not generate a Lua__Label
class. For that, we need to add at least one virtual method. Consider the following example:
class Label : public Widget { private: virtual void add_child(Widget* child); public: void set_text(string p_text); };
In this case, the only virtual method available for the class Lua__Label will be input_event
(inherited from Widget). The reason to declare add_child
as private on the pkg is because if the method is actually private and we don't declare it as such on the pkg, the generated code will try to use it on Lua__Label, and that will produce a compile error.
The file virtual_method_hooks.lua has 3 flags that can be changed (found at the beginning of the file).
disable_virtual_hooks
: a quick flag to disable the whole thing. If it's set to true
, no special code will be generated for virtual methods.
enable_pure_virtual
: enables support for pure virtual methods. If it's set to false
, the output code will be more "conservative" when it comes to classes with pure virtual methods. No constructors will be output, and the code will only compile with GCC 4 (through a preprocessor switch), which is more permissive with pure virtual classes.
default_private_access
: this is a flag to fully enable the code from ToluappClassAccessLabels. By default, tolua++ treats the contents of a class a public
, but since we can have private
virtual methods, there is an option to set the access to private
by default on pkg files too.
Since lua doesn't enforce signatures for functions, the only way to lookup a function is by its name, so when there are more than 1 c++ methods with the same name, your lua function should be prepared to handle all versions of the functions.
Also, when looking for methods on parent classes, only the names are used to match them (this is a limitation of the current version). For example, if you add this to the example package:
class Button : public Widget { public: virtual void add_child(Label* child); };
only the last version of add_child
will be available for the class Lua__Button
.
Only one level of namespaces is supported for the moment. To avoid infinite recursion, only lua functions (and not lua_cfunctions) are called from the virtual methods.
Some versions of tolua++ (like 1.0.92) have problems with the 'default_private_access' flag. If the methods on your virtual class are not being exported, try setting the flag to false
. You'll have to add a private:
label to the class declarations that have private stuff by default at the beginning.
Send questions, bugs, or comments to mailto:puntob@gmail.com