1. 程式人生 > >關於雲風在 Lua 中實現面向物件的原始碼分析

關於雲風在 Lua 中實現面向物件的原始碼分析

①原始碼:

local _class={}
 
function class(super)
	local class_type={}
	class_type.ctor=false
	class_type.super=super
	class_type.new=function(...) 
			local obj={}
			do
				local create
				create = function(c,...)
					if c.super then
						create(c.super,...)
					end
					if c.ctor then
						c.ctor(
obj,...) end end   create(class_type,...) end setmetatable(obj,{ __index=_class[class_type] }) return obj end local vtbl={} _class[class_type]=vtbl   setmetatable(class_type,{__newindex= function(t,k,v) vtbl[k]=v end })   if super then setmetatable(vtbl,{__index=
function(t,k) local ret=_class[super][k] vtbl[k]=ret return ret end }) end   return class_type end

②使用示例:

現在,我們來看看怎麼使用:

base_type=class()		-- 定義一個基類 base_type
 
function base_type:ctor(x)	-- 定義 base_type 的建構函式
	print("base_type ctor")
	self.x=x
end
 
function base_type:print_x(
) -- 定義一個成員函式 base_type:print_x print(self.x) end   function base_type:hello() -- 定義另一個成員函式 base_type:hello print("hello base_type") end

以上是基本的 class 定義的語法,完全相容 lua 的程式設計習慣。我增加了一個叫做 ctor 的詞,作為建構函式的名字。
下面看看怎樣繼承:
test=class(base_type)	-- 定義一個類 test 繼承於 base_type
 
function test:ctor()	-- 定義 test 的建構函式
	print("test ctor")
end
 
function test:hello()	-- 過載 base_type:hello 為 test:hello
	print("hello test")
end

現在可以試一下了:
a=test.new(1)	-- 輸出兩行,base_type ctor 和 test ctor 。這個物件被正確的構造了。
a:print_x()	-- 輸出 1 ,這個是基類 base_type 中的成員函式。
a:hello()	-- 輸出 hello test ,這個函式被過載了。

③原理分析

① 通過引入_class來索引各個類(class_type)的對應的vtbl(裡面記錄了該類的成員變數和成員方法,通過__newindex原方法來實現,攔截對class_type元素的直接賦值轉而儲存在對應的vtbl表中);

② 允許使用者通過重寫class_typector函式來自定義構造過程(主要用於實現成員變數的定義),開放唯一一個例項化函式來讓使用者生成物件例項(該函式的主要任務是遞迴呼叫上層類的ctor函式,並把要返回的物件例項的__index設定為該class_type對應的vtbl)。所以class_type在整個過程中只是只是實現了把物件例項跟vtbl表繫結的任務;

③ 最後,如果該類有父類,就把它的vtbl__index元方法設定為父類的__index。那麼最後呈現出來的結果就是物件例項的__index指向該類對應的vtbl,然後它再指向更上層父類對應的vtbl。任何對類的賦值都被__newindex攔截,從而轉為向對應的vtbl賦值。