lua不是面向对象语言,但可以通过表(table)和元表(metatable)来模拟。table 是 lua 中唯一的一种数据结构,它可以用来描述原始的数组、符号表、集合、 记录、图、树等。每一个tabel都可以附加元表, 元表是带有索引集合的表,它可以改变被附加表的行为。因此,lua可以利用元表来模拟面向对象的行为。首先需要了解下面四个东东:
__index,__newindex,rawgetrawset

__index:是metatable的一个索引,它的值可以是表或者函数,它的作用是什么呢?举一个栗子:

local A = {};
local B = {x=10};
B.__index = B;
setmetatable(A, B);

print(A.x);

打印结果是10,它的查找过程是:首先在表A中查找x,没有找到,继续查找A的元表B,找到元表B的索引__index,此时__index的值是表B,表B是有元素x的,所以打印x的值10。简单总结一下查找表元素的过程:
1. 在表中查找,如果找到,返回该元素,找不到则继续2。
2. 判断该表是否有元表,如果没有元表,返回nil,有元表则继续3 。
3. 判断元表有没有__index,如果__index方法为nil,则返回nil;如果__index的值是一个table,则重复1、2、3;如果__index的值是一个function,则返回该函数的返回值。

__newindex:是metatable的一个索引,跟__index类似,它的值也可以是table或者function,当你给一个不存在的key赋值时,lua会在metatable里查找__newindex。看下面的例子:

local A = {};
local B = {x=10};
B.__newindex = function(t, k, v)
    rawset(t, k, v);
end
setmetatable(A, B);

print(A.y);
A.y = 20;
print(A.y);

第一个print语句,打印是nil,第二个print语句打印出20。__newindex的值在这里是一个函数,有三个参数分别表示:表,键和值。

rawset:可以让你给表的索引赋值时绕过__newindex,如果你在上面的B.__newindex中直接使用t.k = v,会循环调用__newindex产生 stack overflow,rawset可以避免死循环。

rawget:可以绕过__index,如:
print(rawget(A, A.x));
此时打印nil,不会调用元表B的__index。

下面的demo使用lua简单模拟了面向对象的操作。

local Animal = {
	name = "animal";
}

function Animal:eat()
	print("eat: " .. tostring(self.name) );
end

--new函数负责创建Animal对象。
function Animal:new(name)
	local obj = {};

 	--访问表中不存在的k时会调用__index,此时self就是Animal
 	self.__index = self;

 	--对表中不存在的k进行赋值时会调用__newindex
 	self.__newindex = function(t, k, v)
		--可以用来设置一些权限操作
  		if(k == "sayhello") then
  			print("no premission");
  		else
  			--t.k = v;会发生死循环,出现C stack overflow
  			rawset(t ,k ,v);
  		end
	end
	setmetatable(obj, self);
	obj.name = name;
 	return obj;
end

local Bird = {
	flySpeed = 10;
}
--继承Animal
setmetatable(Bird, Animal);

function Bird:new(name, flySpeed)
	local obj = Animal:new(name);
	obj.flySpeed = flySpeed;
	self.__index = self;
	setmetatable(obj, self)
	return obj;
end

function Bird:eat()
	print("eat: " .. tostring(self.name) );
end

function Bird:fly()
	print("name=" .. tostring(self.name) .. "; flySpeed=" .. tostring(self.flySpeed) );
end

local anim = Animal:new("animal");
anim:eat();
anim.sayhello = true;

local bird = Bird:new("bage", 20);
bird:eat();
bird:fly();

运行结果:
eat: animal
no premission
eat: bage
name=bage; flySpeed=20

在c/c++中调用lua函数

上篇文章完成了在lua中调用c/c++函数,现在来实现在c/c++中调用lua函数。 首先完成lua代码,创建sum.lua: function add(x, y) return x + y; end 为了...

阅读全文

在lua中调用c/c++函数

lua是一种轻量级的脚本语言,用来扩展c和c++非常好,在游戏开发中使用很普遍。 首先下载lua,因为我是在win7下,所以我这里下载了luaforwindows,安装到F:\Lu...

阅读全文

c++ 拷贝构造函数

1. 什么是拷贝构造函数 用c++ 创建一个空类的时候,编译器会默认为这个类创建:默认构造函数、析构函数、拷贝构造函数、赋值构造函数。 如: class A{ publi...

阅读全文

欢迎留言