Lua类的实现思路

2.1k 词

复习下lua的元表元方法,浅尝辄止。

目标是用lua实现以下C++例子的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class 
{
public:
std::string mName;

Anima(){}
Anima(const std::string& str) : mName(str) {}

void SetName(const std::string& str);
std::string GetName();
};

class Dog : public Anima
{
public:
std::string mOwnerName;

Dog(){}
Dog(const std::string& str) : Anima(str) {}
void SetOwnerName(const std::string& str);
std::string GetOwnerName()
void PlayBall();
}

Dog dog(std::string("旺财"));
dog.SetOwnerName(std::string("李狗蛋"));
dog:PlayBall();

一、 元表、元方法介绍

lua中的变量是没有数据类型的,但是值具有类型:nil、number、boolean、string、function、thread、userdata和table。lua中的每个值都可以有元表(metatable)。元表定义了原始值在特性操作下的行为。可以在元表中设置特性的字段来改变作用域该值操作的某些行为。如对非数字类型做加法操作时,lua会检查该值的元表中的“add”函数,如果存在,那么则调用其完成加法操作,“add”函数就是元方法(metamethod)。
通过元表和元方法能实现C++的面向对象思想。

一个table默认不带元表,可以通过setmetatable设置元表。

1
2
3
local t = {}
setmetatable(t, t)
print(t == getmetatable) -- true

当我们想要通过继承的思想来访问基类的成员时,会这样写:

1
2
3
4
local A = {}
local B = {x = 10}
setmetatable(A, B)
print(A.x) -- nil

访问A.x时,A中没有x变量。便去A的元表B中查找,然而lua并不会直接在B中查找x,而是通过调用B的元方法index。如果没有index,那么返回nil。如果__index被赋值为一个表,那么就会去这个表中查询:

1
2
3
4
5
local A = {}
local B = {x = 10}
B.__index = B
setmetatable(A, B)
print(A.x) -- 10

如果__index被赋值为一个函数,那么查找的时候就会返回函数的返回值。

1
2
3
4
5
6
7
local A = {}
local B = {x = 10}
B.__index = function(t, key)
print(key .. ' is not exist!')
end
setmetatable(A, B)
print(A.x) -- X is not exist nil

二、lua实现C++继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
local Anima = {mName = ''}
Anima.__index = Anima

function Anima:new(str)
local t = {}

setmetatable(t, self)
if tostring(str) then
self.mName = str
end

return t
end

function Anima:SetName(str)
self.mName = str
end

function Anima:GetName()
return self.mName
end

local Dog = {mOwnerName = ''}
setmetatable(Dog, Anima) --继承基类
Dog.__index = Dog

function Dog:new(name)
local t = Anima:new(name)
setmetatable(t, self)

return t
end

function Dog:SetOwnerName(name)
self.mOwnerName = name
end

function Dog:GetOwnerName()
return self.mOwnerName
end

function Dog:PlayBall()
print(self.mName .. 'is playing with ' .. self.mOwnerName )
end

local dog = Dog:new('旺财')
dog:SetOwnerName('李狗蛋')
dog:PlayBall() -- 旺财is playing with 李狗蛋