Object-oriented in LUA

1. Yuan table

Before understanding object-oriented in Lua, you must first understand the concept of metatable.

The metatable creates a parent-child concept between tables. When our child table performs some specific operations, the content in the metatable will be executed.

1.__tostring and __index

print("--元表操作--")
meta = {
	--当子表被当作字符串调用时,会默认执行tostring函数
	__tostring = function(t)
		return t.name
	end,
	--当子表被当作一个函数使用时,会默认call函数
	__call = function(a,b)
		print(a)
		print(b)
		print("子表被当作函数使用")
	end
}
mytable = {
	name = '我是子表'
}
setmetatable(mytable,meta)--设置元表
print(mytable)
mytable(666);

        It can be found that when the subtable is used as a function, parameters can also be passed. The first parameter defaults to itself, and subsequent parameters can be passed in by calling the subtable function.

2. Operator overloading

        Using operator overloading, we can directly perform operations such as + - */ on the two tables, and we can also perform comparisons such as = <.

        For example, in the following code we can define the return value in the __add function (that is, define the addition operation)

print('--运算符重载--')
meta2 = {
	--使用+时调用add
	__add = function(n1,n2)
		return n1.num_2 + n2.num
	end
	--其他还有 - sub;* mul;/ div;% mod;^ pow;== eq;< lt;<= le;.. concat
}
mytable2_1 = {
	num = 1,
	num_2 = 2
}
mytable2_2 = {
	num = 2
}
setmetatable(mytable2_1,meta2)
setmetatable(mytable2_2,meta2)
print(mytable2_1+mytable2_2)

3.__index specification and __newindex

        When the sub-table cannot find an attribute, it will automatically search in the table specified by __index.

print('--指定操作__index')
meta3 = {
	age = 1
}
--当子表中找不到某一属性时,回到index指定的表中找属性
meta3.__index = meta3

mytable3 = {}
setmetatable(mytable3,meta3)
print(mytable3.age)
--当赋值时,如果赋值一个不存在的索引,那么会把这个值赋到newindex所指的表中
meta3.__newindex = {}
mytable3.number = 3
print(mytable3.number)--此时新定义的number在__newindex指定的新表中
print(meta3.__newindex.number)

4.Other operations

--获取元表
print(getmetatable(mytable3))
--查看自身是否有属性
print(rawget(mytable3,'age'))
--绕过newindex 直接设置自身变量
rawset(mytable3,'age',6)
print(mytable3.age)

2. Object-oriented

Create a table table to act as a class

Object = {
	num = 1,

	fun = function()
		print("这是父类")
	end
}

        1. Encapsulation

        Complete the initial creation of the class by pointing to itself through __index

--------封装-------------
function Object:new()
	local obj = {}

	self.__index = self
	setmetatable(obj,self)
	return obj
end

obj = Object:new()
print(obj.num)

        The output is: 1

        2.Inheritance

        Here, inheritance is mainly achieved by creating a new table (which can be regarded as a class) and also performing metatable creation and __index specified operations for it. Somewhat similar to encapsulation, but here a new table is created. (In this example, a large G table is used to create subclasses)

--------继承-------------
print("继承")
function Object:subClass(className)
	_G[className] ={}

	local obj = _G[className]
	self.__index = self
	obj.base = self
	setmetatable(obj,self)
end

Object:subClass('son')
print(son.num)
son.fun()

Output result: 1
                  This is the parent class

        3. Polymorphism

        In the following example, gameobject acts as the parent class of player and defines a test function in the parent class. To achieve polymorphism, you only need to rewrite the parent class function in the subclass. At the same time, you can also see that the above-mentioned encapsulation and inheritance can also be used normally.

        In addition, there is a pitfall when rewriting the parent class function. Therefore, when we execute the parent class logic, it is best not to use colons but to use dots and then pass the parameters ourselves. The specific reasons can be understood through the code comments below.

--------多态-------------
print("多态")
Object:subClass("gameObject")
function gameObject:test()
	-- body
	print("父类test函数")
end

gameObject:subClass("player")
function player:test()
	--保留父类
	--坑点:这种方法若还有另一个子类p2也执行了修改变量的操作,则修改的变量都是父类的变量
	--换而言之就是两个子类间的修改变量的操作会相互影响
	--因此执行父类逻辑时,最好不用:而是用. 然后自己传参数
	--self.base:test()
	--正确的方式
	self.base.test(self)

	print("子类test函数")
end

local p1 = player:new()
p1:test()

Output result:

Guess you like

Origin blog.csdn.net/YuKar_/article/details/132878716