lua 实现类的继承有三种方法。 第一种拷贝法,把父类的成员拷贝到子类。对象拥有所有成员的独立拷贝。 第二种原型共享法,对象只拥有各自私有的成员如变量,有共性的成员如函数放到原型,元表中。所有该类的对象共享。 第三种混入法,或者掺元法。结合以上两种。开始是原型共享,但当访问到某个父类中才有的变量时,就将其拷贝一份到当前对象, 以后就访问此局部拷贝。 我的想法: 类的数据成员是固定的。 类的方法在一个表中。 所有对象拥有各自的数据成员,拥有共享的方法表。 现在的做法,数据成员和方法混在一个表里。 想象一下 对表的抽象 容器。 如何访问重载。 可以如数组那样顺序存放。 用数字索引。 可以像结构一样,用名字做索引。//偏移优化。偏移模式,可以jit优化。 可以用字符串做索引。 用c++扩展类型,使其像原生类一样操作。 词法,语法分开,两遍式编译。便于增加,修改新的词法元素。 类型信息中说明其是否是属性,是有相应的getter,setter. 可以像表一样。metatable。 现在的做法是对表中不存在的元素才去元表中找__index , __newindex aau 普通类采用拷贝法。 util.declare采用原型共享法。
在table构造器中中以添加静态类型声明,使用类似于C语言中的语法声明API函数需要的结构体(struct)。 通常,我们使用class来定义API函数中需要用到的结构体: //struct 原始结构体class POINT{ int x = 0; //结构体成员必须设定初始值 int y = 0; } //创建一个结构体对象 pt = POINT(); //每个结构体会创建一个_struct只读字段记录类型定义,语义如下: pt = { _struct = "int x;int y" } //////////////////////////////////////////////////// //在API函数中使用结构体 //===================================================== //导入DLL //通常,我们使用class来定义API函数中需要用到的结构体: /* AAuto 允许在table或class成员的键名字前面添加一个描述性标识符,标识符遵循普通变量命名规则。 //创建一个新的结构体 //使用API函数 io.print(p.x,p.y) /////////////////////////////////////////////////////////////////////////////////////////////////////// 例子 import mouse; import console; class POINT{ int x; int y; print = function(){ self.print( this.x,this.y ); } } namespace POINT { print = ..console.log; } //创建结构体对象 var point = POINT(); //调用 WINAPI ::GetCursorPos(point) //::GetCursor = u.api("GetCursor","pointer()") //调用对象成员函数 point.print() /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// lua实现 http:///ext_ffi_tutorial.html Defining Metamethods for a C TypeThe following code explains how to define metamethods for a C type. We define a simple point type and add some operations to it: local ffi = require("ffi")
ffi.cdef[[
typedef struct { double x, y; } point_t;
]]
local point
local mt = {
__add = function(a, b) return point(a.x+b.x, a.y+b.y) end,
__len = function(a) return math.sqrt(a.x*a.x + a.y*a.y) end,
__index = {
area = function(a) return a.x*a.x + a.y*a.y end,
},
}
point = ffi.metatype("point_t", mt)
local a = point(3, 4)
print(a.x, a.y) --> 3 4
print(#a) --> 5
print(a:area()) --> 25
local b = a + point(0.5, 8)
print(#b) --> 12.5
Here's the step-by-step explanation: ① This defines the C type for a two-dimensional point object. ② We have to declare the variable holding the point constructor first, because it's used inside of a metamethod. ③ Let's define an __add metamethod which adds the coordinates of two points and creates a new point object. For simplicity, this function assumes that both arguments are points. But it could be any mix of objects, if at least one operand is of the required type (e.g. adding a point plus a number or vice versa). Our __len metamethod returns the distance of a point to the origin. ④ If we run out of operators, we can define named methods, too. Here the __index table defines an area function. For custom indexing needs, one might want to define __index and __newindex functions instead. ⑤ This associates the metamethods with our C type. This only needs to be done once. For convenience, a constructor is returned by ffi.metatype(). We're not required to use it, though. The original C type can still be used e.g. to create an array of points. The metamethods automatically apply to any and all uses of this type. Please note that the association with a metatable is permanent and the metatable must not be modified afterwards! Ditto for the __index table. ⑥ Here are some simple usage examples for the point type and their expected results. The pre-defined operations (such as a.x) can be freely mixed with the newly defined metamethods. Note that area is a method and must be called with the Lua syntax for methods: a:area(), not a.area(). The C type metamethod mechanism is most useful when used in conjunction with C libraries that are written in an object-oriented style. Creators return a pointer to a new instance and methods take an instance pointer as the first argument. Sometimes you can just point __index to the library namespace and __gc to the destructor and you're done. But often enough you'll want to add convenience wrappers, e.g. to return actual Lua strings or when returning multiple values. Some C libraries only declare instance pointers as an opaque void * type. In this case you can use a fake type for all declarations, e.g. a pointer to a named (incomplete) struct will do: typedef struct foo_type *foo_handle. The C side doesn't know what you declare with the LuaJIT FFI, but as long as the underlying types are compatible, everything still works. Translating C IdiomsHere's a list of common C idioms and their translation to the LuaJIT FFI:
To Cache or Not to CacheIt's a common Lua idiom to cache library functions in local variables or upvalues, e.g.: local byte, char = string.byte, string.char local function foo(x) return char(byte(x)+1) end This replaces several hash-table lookups with a (faster) direct use of a local or an upvalue. This is less important with LuaJIT, since the JIT compiler optimizes hash-table lookups a lot and is even able to hoist most of them out of the inner loops. It can't eliminate all of them, though, and it saves some typing for often-used functions. So there's still a place for this, even with LuaJIT. The situation is a bit different with C function calls via the FFI library. The JIT compiler has special logic to eliminate all of the lookup overhead for functions resolved from a C library namespace! Thus it's not helpful and actually counter-productive to cache individual C functions like this: local funca, funcb = ffi.C.funcb, ffi.C.funcb -- Not helpful!
local function foo(x, n)
for i=1,n do funcb(funca(x, i), 1) end
end
This turns them into indirect calls and generates bigger and slower machine code. Instead you'll want to cache the namespace itself and rely on the JIT compiler to eliminate the lookups: local C = ffi.C -- Instead use this!
local function foo(x, n)
for i=1,n do C.funcb(C.funca(x, i), 1) end
end
This generates both shorter and faster code. So don't cache C functions, but do cache namespaces! Most often the namespace is already in a local variable at an outer scope, e.g. from local lib = ffi.load(...). Note that copying it to a local variable in the function scope is unnecessary. namespace raw class struct { ctor( cls ) { var tcls = type(cls); var struct = class { ctor( ... ){ if( tcls = "class"){ this[["_object"]] = cls( ... ) } else { this[["_object"]] = ..table.mixin({},cls,...); } this[["_struct_cdata"]] = ..raw.malloc(this[["_object"]]) }; @_meta; } struct._meta = _meta; return struct; }; } namespace struct{ var convert = ..raw.convert; var mixin = ..raw.mixin; _meta = { _topointer = function(){ return owner[["_struct_cdata"]]; } _get = function(k){ var obj = owner[["_object"]]; convert(owner[["_struct_cdata"]],obj); return obj[k] } _set = function( k, v ){ var obj = owner[["_object"]]; var handle = owner[["_struct_cdata"]]; mixin(handle,obj,{[k] = v } ) } } } /**intellisense() raw.struct = 将结构体转换为原始结构体\n原始结构体创建的对象会分配一块固定的内存\n可用于API参数pointer类型实参并自动转换为C指针 raw.struct(__/*结构体*/) = 分配内存,创建并返回静态类,\n参数可以是定义了静态类型的类(结构体)\n也可以是声明了静态类型的table原型表,\n如果参数是原型表,则会创建一个默认的构造函数\n默认构造函数将接收参数混入原型创建新对象 end intellisense**/
|
|