我在调用继承链时遇到了一些奇怪的事情。
假设我有以下内容:
local Animal = classes.class()
local numAnimals = 0
function Animal:init (name)
self.name = name
numAnimals = numAnimals + 1
self.id = numAnimals
end
local Cat = classes.class(Animal)
function Cat:init(name, breed)
self.super:init(name)
self.breed = breed
end
创建实例时,这样就可以了。但是假设在
Animal:init
里面我想在分配后引用self.id
,用它做一些事情,当最初从Cat:init
调用时:
local Animal = classes.class()
local numAnimals = 0
function Animal:init (name)
self.name = name
numAnimals = numAnimals + 1
self.id = numAnimals
print('My ID is '..self.id) -- this returns an error and self.id is nil
end
local Cat = classes.class(Animal)
function Cat:init(name, breed)
self.super:init(name)
self.breed = breed
end
出于某种原因,当调用
self.super:init(name)
时,引用超类init
中的实例属性将它们作为nil
。对正在发生的事情有什么想法吗?我相信这个问题在“错误修复”部分here中有所描述,其中使用实例变量覆盖的超类函数有一个错误。虽然有针对该问题的定义修复,但不确定它是否实际适用,因为该文章的参考代码不再可用。
local classes = {}
classes.Object = {}
classes.Object.class = classes.Object
function classes.Object:init (...)
end
function classes.Object.alloc (mastertable)
return setmetatable({}, {__index = classes.Object, __newindex = mastertable})
end
function classes.Object.new (...)
return classes.Object.alloc({}):init(...)
end
function classes.Object:instanceOf (class)
if self.class == class then
return true
end
if self.super then
return self.super:instanceOf(class)
end
return false
end
function classes.class (baseclass)
local classdef = {}
baseclass = baseclass or classes.Object
setmetatable(classdef, {__index = baseclass})
classdef.class = classdef
function classdef.alloc (mastertable)
local instance = {super = baseclass.alloc(mastertable)}
setmetatable(instance, {__index = classdef, __newindex = mastertable})
return instance
end
function classdef.new (...)
local instance = {}
instance.super = baseclass.alloc(instance)
setmetatable(instance, {__index = classdef})
instance:init(...)
return instance
end
return classdef
end
错误在行中
self.super:init(name)
self.super
这里是(父)类,但是 init
必须应用于正在初始化的实例,而不是类。
您使用的 OOP 实现很奇怪。
super
字段是指向某个代理的指针,该代理无法读取刚刚写入的内容。并且为每个正在创建的类实例分配一个新的代理。我不明白该设计决定背后的原因。
下面是另一个非常简单的 Lua OOP 实现:
-------- Simple Lua OOP
local BaseClass = {}
BaseClass.class = BaseClass
function BaseClass:init(...)
end
function BaseClass:new(...)
local instance = setmetatable({}, {__index = self})
instance:init(...)
return instance
end
function BaseClass:instanceOf(class)
if self.class == class then
return true
end
if self.super then
return self.super:instanceOf(class)
end
return false
end
function BaseClass:createSubClass()
local SubClass = {}
SubClass.class = SubClass
SubClass.super = self
return setmetatable(SubClass, {__index = self})
end
-------- Usage Example
local Animal = BaseClass:createSubClass()
local numAnimals = 0
function Animal:init(name)
-- self = the instance to be initialized
self.name = name
numAnimals = numAnimals + 1
self.id = numAnimals
print('My ID is '..self.id)
end
local Cat = Animal:createSubClass()
function Cat:init(name, breed)
-- self = the instance to be initialized
-- self.super = the parent class of the class of the instance
self.super.init(self, name)
self.breed = breed
end
local cat = Cat:new("cat name", "cat breed")