在超类函数调用中分配的实例变量被访问为 nil

问题描述 投票:0回答:1

问题

我在调用继承链时遇到了一些奇怪的事情。

假设我有以下内容:

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
inheritance lua
1个回答
0
投票
  1. 错误在行中

    self.super:init(name)

    self.super
    这里是(父)类,但是
    init
    必须应用于正在初始化的实例,而不是类。

  2. 您使用的 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")
© www.soinside.com 2019 - 2024. All rights reserved.