-- class.lua
-- Compatible with Lua 5.1 (not 5.0).
function class(base, init)
    local c = {}    -- a new class instance
    if not init and type(base) == 'function' then
        init = base
        base = nil
    elseif type(base) == 'table' then
        -- our new class is a shallow copy of the base class!
        for i, v in pairs(base) do
            c[i] = v
        end
        c._base = base
    end
    -- the class will be the metatable for all its objects,
    -- and they will look up their methods in it.
    c.__index = c

    c.init = init
    c.is_a = function(self, klass)
        local m = getmetatable(self)
        while m do
            if m == klass then
                return true
            end
            m = m._base
        end
        return false
    end
    
    
    function c._get_value(_wrap, key)
      local value = _wrap[key]
      if not value then
        value = c[key]
      end      
      return value
    end
    
    function c._set_value(_wrap, key,value)
      _wrap[key] = value
    end
    
    c.__index = function(tbl, key)      
      local _get_value = rawget(c, "_get_value")
      if not _get_value then
        return
      end
      local get_value = c.get_value
      local _wrap = rawget(c, "_wrap")
      if get_value then
        return c:get_value(_get_value,_wrap, key)
      elseif _get_value then
        return c:_get_value(_wrap, key)
      end  
    end
    c.__newindex = function(tbl, key, value)
      local _wrap = rawget(c, "_wrap")
      if not _wrap then
        _wrap = {}
        rawset(c, "_wrap", _wrap)
      end
      
      local _set_value = rawget(c, "_set_value")
      if not _set_value  then
        return
      end
      local set_value = c.set_value
      if set_value then
        c:set_value(_set_value, _wrap, key, value)
      elseif _set_value then
        c:_set_value(_wrap, key, value)
      end
    end
  
    local mt = {}
    mt.__call = function(class_tbl, ...)
        local obj = {}
        setmetatable(obj, c)
        if init then
            init(obj, ...)
        else
            -- make sure that any stuff from the base class is initialized!
            if base and base.init then
                base.init(obj, ...)
            end
        end
        return obj
    end
    setmetatable(c, mt)
    return c
end

local Object = class(function(tbl, name) 
    tbl.name = name
end)

local GameObject = class(Object, function(tbl, name, age) 
  Object.init(tbl, name)
  tbl.age = age
end)

function GameObject:set_value(base_func, _wrap, key, value)
  base_func(_wrap, key, value)
  print("set", base_func, _wrap, key, value)
end

function GameObject:get_value(base_func, _wrap, key)
  print("get", base_func, _wrap, key)
  return base_func(_wrap, key, value)  
end

function GameObject:AddAge(age)
  self.age = self.age + age
end


local go = GameObject("name111", 150)
print(go.name, go.age)
go.x = 123
print(go.x)
local go1 = GameObject("name222", 23)
print(go.name, go.age)

local Transform = class(GameObject)
function Transform:AddAge(age)
  self.age = self.age + (age * 2)
end
local tr1 = Transform("nameTra", 1123)
print(tr1.name, tr1.age)
tr1:AddAge(2)
print(tr1.name, tr1.age)

输出:

> set    function: 0x00028a90    table: 0x0002b288    name    name111
> set    function: 0x00028a90    table: 0x0002b288    age    150
> get    function: 0x00028a70    table: 0x0002b288    name
> get    function: 0x00028a70    table: 0x0002b288    age
> name111    150
> set    function: 0x00028a90    table: 0x0002b288    x    123
> get    function: 0x00028a70    table: 0x0002b288    x
> 123
> set    function: 0x00028a90    table: 0x0002b288    name    name222
> set    function: 0x00028a90    table: 0x0002b288    age    23
> get    function: 0x00028a70    table: 0x0002b288    name
> get    function: 0x00028a70    table: 0x0002b288    age
> name222    23
> set    function: 0x0002b2b0    table: 0x0002b288    name    nameTra
> set    function: 0x0002b2b0    table: 0x0002b288    age    1123
> get    function: 0x000212f0    table: 0x0002b288    name
> get    function: 0x000212f0    table: 0x0002b288    age
> nameTra    1123
> get    function: 0x000212f0    table: 0x0002b288    AddAge
> get    function: 0x000212f0    table: 0x0002b288    age
> set    function: 0x0002b2b0    table: 0x0002b288    age    1127
> get    function: 0x000212f0    table: 0x0002b288    name
> get    function: 0x000212f0    table: 0x0002b288    age
> nameTra    1127